1use core::cell::UnsafeCell;
6use core::hint::spin_loop;
7use core::ops::{Deref, DerefMut};
8use core::ptr;
9use core::sync::atomic::{AtomicUsize, AtomicPtr, Ordering};
10
11type LockPtr = *const AtomicUsize;
13type DataPtr<T> = *const UnsafeCell<T>;
14
15const UNLOCKED: usize = 0;
17const WRITE_LOCKED: usize = usize::MAX; #[derive(Debug, Clone, Copy, PartialEq, Eq)]
21enum MutexState {
22 Uninitialized,
24 Local,
26 Mirrored,
28}
29
30#[derive(Debug)]
63pub struct SharedMutex<T> {
64 lock_ptr: LockPtr,
66 data_ptr: DataPtr<T>,
68 state: MutexState,
70 local_lock_storage: AtomicUsize,
72 local_data_storage: Option<UnsafeCell<T>>,
74}
75
76impl<T> Default for SharedMutex<T> {
78 fn default() -> Self {
79 Self::new()
80 }
81}
82
83impl<T> SharedMutex<T> {
84 #[inline]
86 pub const fn new() -> SharedMutex<T> {
87 SharedMutex {
88 lock_ptr: ptr::null(),
89 data_ptr: ptr::null(),
90 state: MutexState::Uninitialized,
91 local_lock_storage: AtomicUsize::new(UNLOCKED),
92 local_data_storage: None,
93 }
94 }
95
96 pub fn set(&mut self, t: T) {
98 if self.state != MutexState::Uninitialized {
99 panic!("SharedMutex may only be initialized once (using set or mirror)");
100 }
101 self.local_data_storage = Some(UnsafeCell::new(t));
102 self.local_lock_storage.store(UNLOCKED, Ordering::Relaxed);
103 self.lock_ptr = &self.local_lock_storage as *const AtomicUsize;
104 self.data_ptr = self.local_data_storage.as_ref().unwrap() as *const UnsafeCell<T>;
105 self.state = MutexState::Local;
106 }
107
108 pub fn share(&self) -> (u64, u64) {
110 if self.state != MutexState::Local {
111 panic!("Only a locally set SharedMutex can be shared (must be initialized with `set`)");
112 }
113 debug_assert!(!self.lock_ptr.is_null(), "Internal error: null lock_ptr in Local state for share()");
114 debug_assert!(!self.data_ptr.is_null(), "Internal error: null data_ptr in Local state for share()");
115 (self.lock_ptr as u64, self.data_ptr as u64)
116 }
117
118 pub unsafe fn mirror(&mut self, lock_addr: u64, data_addr: u64) {
120 if self.state != MutexState::Uninitialized {
121 panic!("SharedMutex may only be initialized once (using set or mirror)");
122 }
123 if lock_addr == 0 || data_addr == 0 {
124 panic!("Cannot mirror using null addresses (lock_addr={}, data_addr={})", lock_addr, data_addr);
125 }
126 self.lock_ptr = lock_addr as LockPtr;
127 self.data_ptr = data_addr as DataPtr<T>;
128 self.state = MutexState::Mirrored;
129 self.local_data_storage = None;
130 }
131
132 #[inline]
134 pub fn lock(&self) -> SharedMutexGuard<'_, T> {
135 if !self.is_initialized() {
136 panic!("Cannot lock an uninitialized SharedMutex (call `set` or `mirror` first)");
137 }
138 debug_assert!(!self.lock_ptr.is_null(), "Internal error: null lock_ptr in lock()");
139 debug_assert!(!self.data_ptr.is_null(), "Internal error: null data_ptr in lock()");
140 loop {
141 match unsafe { (*self.lock_ptr).compare_exchange_weak(
142 UNLOCKED,
143 WRITE_LOCKED,
144 Ordering::Acquire,
145 Ordering::Relaxed,
146 )} {
147 Ok(_) => return SharedMutexGuard { mutex: self },
148 Err(_) => spin_loop(),
149 }
150 }
151 }
152
153 #[inline]
155 pub fn read(&self) -> SharedMutexReadGuard<'_, T> {
156 if !self.is_initialized() {
157 panic!("Cannot read-lock an uninitialized SharedMutex (call `set` or `mirror` first)");
158 }
159 debug_assert!(!self.lock_ptr.is_null(), "Internal error: null lock_ptr in read()");
160 debug_assert!(!self.data_ptr.is_null(), "Internal error: null data_ptr in read()");
161 loop {
162 let current_state = unsafe { (*self.lock_ptr).load(Ordering::Relaxed) };
163 if current_state == WRITE_LOCKED {
164 spin_loop();
165 continue;
166 }
167 if current_state == WRITE_LOCKED - 1 {
168 spin_loop();
170 continue;
171 }
172 match unsafe { (*self.lock_ptr).compare_exchange_weak(
173 current_state,
174 current_state + 1,
175 Ordering::Acquire,
176 Ordering::Relaxed,
177 )} {
178 Ok(_) => return SharedMutexReadGuard { mutex: self },
179 Err(_) => spin_loop(),
180 }
181 }
182 }
183
184 #[inline]
186 fn release_write_lock(&self) {
187 debug_assert!(self.is_initialized(), "Attempted to release write lock on uninitialized mutex");
188 debug_assert!(!self.lock_ptr.is_null(), "Attempted to release write lock with a null lock_ptr");
189 unsafe { (*self.lock_ptr).store(UNLOCKED, Ordering::Release); }
190 }
191
192 #[inline]
194 fn release_read_lock(&self) {
195 debug_assert!(self.is_initialized(), "Attempted to release read lock on uninitialized mutex");
196 debug_assert!(!self.lock_ptr.is_null(), "Attempted to release read lock with a null lock_ptr");
197 unsafe { (*self.lock_ptr).fetch_sub(1, Ordering::Release); }
198 }
199
200 #[inline]
202 pub fn is_locked(&self) -> bool {
203 if !self.is_initialized() {
204 panic!("Cannot check lock status of an uninitialized SharedMutex");
205 }
206 debug_assert!(!self.lock_ptr.is_null(), "Internal error: null lock_ptr in is_locked()");
207 unsafe { (*self.lock_ptr).load(Ordering::Acquire) != UNLOCKED }
208 }
209
210 #[inline]
212 pub fn is_initialized(&self) -> bool {
213 self.state != MutexState::Uninitialized
214 }
215}
216
217#[derive(Debug)]
219#[must_use = "if unused the Mutex will immediately unlock"]
220pub struct SharedMutexGuard<'a, T> {
221 mutex: &'a SharedMutex<T>,
222}
223
224impl<T> Deref for SharedMutexGuard<'_, T> {
225 type Target = T;
226 #[inline]
227 fn deref(&self) -> &Self::Target {
228 unsafe {
229 debug_assert!(self.mutex.is_initialized(), "WriteGuard exists for uninitialized mutex");
230 debug_assert!(!self.mutex.data_ptr.is_null(), "WriteGuard exists with null data_ptr");
231 &*(*self.mutex.data_ptr).get()
232 }
233 }
234}
235
236impl<T> DerefMut for SharedMutexGuard<'_, T> {
237 #[inline]
238 fn deref_mut(&mut self) -> &mut Self::Target {
239 unsafe {
240 debug_assert!(self.mutex.is_initialized(), "WriteGuard exists for uninitialized mutex");
241 debug_assert!(!self.mutex.data_ptr.is_null(), "WriteGuard exists with null data_ptr");
242 &mut *(*self.mutex.data_ptr).get()
243 }
244 }
245}
246
247impl<T> Drop for SharedMutexGuard<'_, T> {
248 #[inline]
249 fn drop(&mut self) {
250 if self.mutex.is_initialized() {
251 self.mutex.release_write_lock();
252 }
253 }
254}
255
256#[derive(Debug)]
258#[must_use = "if unused the Mutex will immediately unlock"]
259pub struct SharedMutexReadGuard<'a, T> {
260 mutex: &'a SharedMutex<T>,
261}
262
263impl<T> Deref for SharedMutexReadGuard<'_, T> {
264 type Target = T;
265 #[inline]
266 fn deref(&self) -> &Self::Target {
267 unsafe {
268 debug_assert!(self.mutex.is_initialized(), "ReadGuard exists for uninitialized mutex");
269 debug_assert!(!self.mutex.data_ptr.is_null(), "ReadGuard exists with null data_ptr");
270 &*(*self.mutex.data_ptr).get()
271 }
272 }
273}
274
275impl<T> Drop for SharedMutexReadGuard<'_, T> {
276 #[inline]
277 fn drop(&mut self) {
278 if self.mutex.is_initialized() {
279 self.mutex.release_read_lock();
280 }
281 }
282}
283
284unsafe impl<T: Send> Send for SharedMutex<T> {}
286unsafe impl<T: Send> Sync for SharedMutex<T> {}
287unsafe impl<'a, T: Send> Send for SharedMutexGuard<'a, T> {}
288unsafe impl<'a, T: Send + Sync> Sync for SharedMutexGuard<'a, T> {}
289unsafe impl<'a, T: Send> Send for SharedMutexReadGuard<'a, T> {}
290unsafe impl<'a, T: Send + Sync> Sync for SharedMutexReadGuard<'a, T> {}
291
292const GLOBAL_UNINITIALIZED: usize = 0;
298const GLOBAL_INITIALIZING: usize = 1;
299const GLOBAL_INITIALIZED: usize = 2;
300
301#[derive(Debug)]
335pub struct GlobalSharedMutex<T> {
336 state: AtomicUsize,
337 ptr: AtomicPtr<SharedMutex<T>>,
338}
339
340impl<T> GlobalSharedMutex<T> {
341 pub const fn new() -> Self {
344 Self {
345 state: AtomicUsize::new(GLOBAL_UNINITIALIZED),
346 ptr: AtomicPtr::new(ptr::null_mut()),
347 }
348 }
349
350 pub fn init(&self, data: T) {
356 match self.state.compare_exchange(
358 GLOBAL_UNINITIALIZED,
359 GLOBAL_INITIALIZING,
360 Ordering::Acquire, Ordering::Relaxed, ) {
363 Ok(_) => { let mut boxed_sm = Box::new(SharedMutex::<T>::new());
367
368 boxed_sm.set(data); self.ptr.store(Box::into_raw(boxed_sm), Ordering::Release);
375
376 self.state.store(GLOBAL_INITIALIZED, Ordering::Release); }
379 Err(current_state) => {
380 if current_state == GLOBAL_INITIALIZING {
381 while self.state.load(Ordering::Acquire) == GLOBAL_INITIALIZING {
382 core::hint::spin_loop();
383 }
384 if self.state.load(Ordering::Relaxed) != GLOBAL_INITIALIZED {
385 panic!("GlobalSharedMutex failed to initialize correctly after spinning.");
386 }
387 } else if current_state == GLOBAL_INITIALIZED {
388 panic!("GlobalSharedMutex::init called more than once or on an already initialized mutex.");
389 } else {
390 panic!("GlobalSharedMutex in unexpected state during init: {}", current_state);
391 }
392 }
393 }
394 }
395
396 #[inline]
401 fn get_mutex(&self) -> &SharedMutex<T> {
402 loop {
403 match self.state.load(Ordering::Acquire) {
404 GLOBAL_INITIALIZED => {
405 let ptr = self.ptr.load(Ordering::Acquire);
406 debug_assert!(!ptr.is_null(), "GlobalSharedMutex ptr is null despite being initialized");
413 return unsafe { &*ptr };
414 }
415 GLOBAL_INITIALIZING => {
416 spin_loop(); }
418 GLOBAL_UNINITIALIZED => {
419 panic!("GlobalSharedMutex has not been initialized. Call init() first.");
420 }
421 _ => unreachable!("GlobalSharedMutex in invalid state"),
422 }
423 }
424 }
425
426 pub fn lock(&self) -> SharedMutexGuard<'_, T> {
430 self.get_mutex().lock()
431 }
432
433 pub fn read(&self) -> SharedMutexReadGuard<'_, T> {
437 self.get_mutex().read()
438 }
439
440 pub fn share(&self) -> (u64, u64) {
444 self.get_mutex().share()
445 }
446
447 pub fn is_locked(&self) -> bool {
451 self.get_mutex().is_locked()
452 }
453}
454
455unsafe impl<T: Send> Send for GlobalSharedMutex<T> {}
465unsafe impl<T: Send> Sync for GlobalSharedMutex<T> {}
466
467#[cfg(test)]
472mod tests {
473 use super::*;
474 use std::sync::Arc;
475 use std::thread;
476 use std::time::Duration;
477
478 #[derive(Debug, Default, Clone, PartialEq)]
479 pub struct TestData {
480 pub value: i32,
481 pub text: String,
482 }
483
484 #[test]
486 fn basic_write_lock_unlock() {
487 let mut mutex = SharedMutex::new();
488 mutex.set(TestData { value: 10, text: "hello".to_string() });
489
490 {
491 let mut guard = mutex.lock(); assert_eq!(guard.value, 10);
493 guard.value = 20;
494 guard.text = "world".to_string();
495 } {
498 let guard = mutex.lock(); assert_eq!(guard.value, 20);
500 assert_eq!(guard.text, "world");
501 }
502 }
503
504 #[test]
505 fn basic_read_lock_unlock() {
506 let mut mutex = SharedMutex::new();
507 mutex.set(TestData { value: 30, text: "read test".to_string() });
508
509 {
510 let guard = mutex.read(); assert_eq!(guard.value, 30);
512 assert_eq!(guard.text, "read test");
513 } let r1 = mutex.read();
517 let r2 = mutex.read();
518 assert_eq!(r1.value, 30);
519 assert_eq!(r2.value, 30);
520 drop(r1);
521 drop(r2);
522 }
523
524 #[test]
525 fn write_blocks_read() {
526 let mut m = SharedMutex::new();
527 m.set(TestData::default());
528 let mutex = Arc::new(m);
529
530 let writer_mutex_ref = Arc::clone(&mutex);
531 let _write_guard = writer_mutex_ref.lock();
532
533 let reader_mutex_ref = Arc::clone(&mutex);
534 let reader_thread = thread::spawn(move || {
535 let start_time = std::time::Instant::now();
536 let _read_guard = reader_mutex_ref.read();
537 assert!(start_time.elapsed() > Duration::from_millis(50), "Reader did not block for writer");
538 });
539
540 thread::sleep(Duration::from_millis(100));
541 drop(_write_guard);
542
543 reader_thread.join().unwrap();
544 }
545
546 #[test]
547 fn read_blocks_write() {
548 let mut m = SharedMutex::new();
549 m.set(TestData::default());
550 let mutex = Arc::new(m);
551
552 let reader_mutex_ref = Arc::clone(&mutex);
553 let _read_guard = reader_mutex_ref.read();
554
555 let writer_mutex_ref = Arc::clone(&mutex);
556 let writer_thread = thread::spawn(move || {
557 let start_time = std::time::Instant::now();
558 let mut _write_guard = writer_mutex_ref.lock();
559 _write_guard.value = 100;
560 assert!(start_time.elapsed() > Duration::from_millis(50), "Writer did not block for reader");
561 });
562
563 thread::sleep(Duration::from_millis(100));
564 drop(_read_guard);
565
566 writer_thread.join().unwrap();
567
568 let final_read = mutex.read();
569 assert_eq!(final_read.value, 100);
570 }
571
572 #[test]
573 fn multiple_readers_concurrently() {
574 let mut m = SharedMutex::new();
575 m.set(TestData { value: 123, text: "concurrent".to_string() });
576 let mutex = Arc::new(m);
577 let barrier = Arc::new(std::sync::Barrier::new(5));
578 let mut handles = vec![];
579
580 for _i in 0..5 {
581 let reader_mutex_ref = Arc::clone(&mutex);
582 let barrier_clone = Arc::clone(&barrier);
583 let handle = thread::spawn(move || {
584 barrier_clone.wait();
585 let guard = reader_mutex_ref.read();
586 assert_eq!(guard.value, 123);
587 assert_eq!(guard.text, "concurrent");
588 thread::sleep(Duration::from_millis(50));
589 drop(guard);
590 });
591 handles.push(handle);
592 }
593
594 for handle in handles {
595 handle.join().unwrap();
596 }
597 }
598
599 #[test]
600 fn is_locked_behavior() {
601 let mut mutex = SharedMutex::new();
602 mutex.set(TestData::default());
603
604 assert!(!mutex.is_locked(), "Should not be locked initially after set");
605
606 let r_guard = mutex.read();
607 assert!(mutex.is_locked(), "Should be locked after acquiring read lock");
608 drop(r_guard);
609 assert!(!mutex.is_locked(), "Should not be locked after read lock released");
610
611 let w_guard = mutex.lock();
612 assert!(mutex.is_locked(), "Should be locked after acquiring write lock");
613 drop(w_guard);
614 assert!(!mutex.is_locked(), "Should not be locked after write lock released");
615 }
616
617 #[test]
618 fn shared_mutex_can_be_static_like() {
619 let mut local_static_sim_owner = Box::new(SharedMutex::<i32>::new());
620 local_static_sim_owner.set(100);
621
622 let local_static_sim: &SharedMutex<i32> = &*local_static_sim_owner;
623
624 let _r = local_static_sim.read();
625 assert_eq!(*_r, 100);
626 drop(_r);
627
628 let mut _w = local_static_sim_owner.lock();
629 *_w = 200;
630 drop(_w);
631
632 let _r2 = local_static_sim.read();
633 assert_eq!(*_r2, 200);
634 }
635
636 #[test]
637 fn mirror_test() {
638 let mut original_mutex_owner = Box::new(SharedMutex::<TestData>::new());
639 original_mutex_owner.set(TestData { value: 1000, text: "original".to_string() });
640
641 let (lock_addr, data_addr) = original_mutex_owner.share();
642
643 let mut mirrored_mutex = SharedMutex::<TestData>::new();
644 unsafe {
645 mirrored_mutex.mirror(lock_addr, data_addr);
646 }
647
648 {
649 let guard = mirrored_mutex.read();
650 assert_eq!(guard.value, 1000);
651 assert_eq!(guard.text, "original");
652 }
653 {
654 let mut guard = original_mutex_owner.lock();
655 guard.value = 2000;
656 guard.text = "modified by original".to_string();
657 }
658 {
659 let guard = mirrored_mutex.read();
660 assert_eq!(guard.value, 2000);
661 assert_eq!(guard.text, "modified by original");
662 }
663 {
664 let mut guard = mirrored_mutex.lock();
665 guard.value = 3000;
666 guard.text = "modified by mirror".to_string();
667 }
668 {
669 let guard = original_mutex_owner.read();
670 assert_eq!(guard.value, 3000);
671 assert_eq!(guard.text, "modified by mirror");
672 }
673 }
674
675 #[test]
676 #[should_panic(expected = "SharedMutex may only be initialized once")]
677 fn set_twice_panics() {
678 let mut m = SharedMutex::<i32>::new();
679 m.set(10);
680 m.set(20);
681 }
682
683 #[test]
684 #[should_panic(expected = "SharedMutex may only be initialized once")]
685 unsafe fn mirror_after_set_panics() {
686 let mut m1 = SharedMutex::<i32>::new();
687 m1.set(10);
688 let (l,d) = m1.share();
689
690 let mut m2 = SharedMutex::<i32>::new();
691 m2.set(20);
692 m2.mirror(l,d);
693 }
694
695 #[test]
696 #[should_panic(expected = "Cannot lock an uninitialized SharedMutex")]
697 fn lock_uninitialized_panics() {
698 let m = SharedMutex::<i32>::new();
699 let _g = m.lock();
700 }
701
702 #[test]
703 #[should_panic(expected = "Cannot read-lock an uninitialized SharedMutex")]
704 fn read_uninitialized_panics() {
705 let m = SharedMutex::<i32>::new();
706 let _g = m.read();
707 }
708
709 #[test]
710 #[should_panic(expected = "Only a locally set SharedMutex can be shared")]
711 fn share_uninitialized_panics() {
712 let m = SharedMutex::<i32>::new();
713 m.share();
714 }
715
716 #[test]
717 #[should_panic(expected = "Only a locally set SharedMutex can be shared")]
718 unsafe fn share_mirrored_panics() {
719 let mut original = Box::new(SharedMutex::<i32>::new());
720 original.set(1);
721 let (l,d) = original.share();
722
723 let mut mirrored = SharedMutex::<i32>::new();
724 mirrored.mirror(l,d);
725 mirrored.share();
726 }
727}
728
729#[cfg(test)]
730mod global_tests {
731 use super::*;
733 use std::sync::Arc;
734 use std::thread;
735 static GLOBAL_INT_MUTEX_FOR_BASIC_TEST: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
740
741 #[test]
742 fn g_basic_init_lock_read() {
743 let test_static_mutex: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
752 test_static_mutex.init(100); {
755 let mut guard = test_static_mutex.lock();
756 assert_eq!(*guard, 100);
757 *guard = 200;
758 }
759 {
760 let guard = test_static_mutex.read();
761 assert_eq!(*guard, 200);
762 }
763 }
764
765 #[test]
766 #[should_panic(expected = "GlobalSharedMutex::init called more than once")]
767 fn g_double_init_panics() {
768 let temp_global: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
773 temp_global.init(1);
774 temp_global.init(2); }
776
777 #[test]
778 #[should_panic(expected = "GlobalSharedMutex has not been initialized")]
779 fn g_lock_before_init_panics() {
780 let temp_global: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
781 let _guard = temp_global.lock(); }
783
784 #[test]
785 #[should_panic(expected = "GlobalSharedMutex has not been initialized")]
786 fn g_read_before_init_panics() {
787 let temp_global: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
788 let _guard = temp_global.read(); }
790
791 #[test]
792 fn g_multithreaded_access() {
793 let local_global_mutex: Arc<GlobalSharedMutex<i32>> = Arc::new(GlobalSharedMutex::new());
794 local_global_mutex.init(0);
795
796 let mut handles = vec![];
797
798 for i in 0..10 {
799 let mutex_clone = Arc::clone(&local_global_mutex);
800 let handle = thread::spawn(move || {
801 for _ in 0..100 {
802 let mut guard = mutex_clone.lock();
803 *guard += 1;
804 if i == 0 && *guard % 10 == 0 {
805 drop(guard);
806 let r_guard = mutex_clone.read();
807 assert!(*r_guard > 0);
808 }
809 }
810 });
811 handles.push(handle);
812 }
813
814 for handle in handles {
815 handle.join().unwrap();
816 }
817
818 let final_guard = local_global_mutex.lock();
819 assert_eq!(*final_guard, 10 * 100);
820 }
821
822 #[test]
823 fn g_share_and_mirror_works() {
824 let local_global_owner: GlobalSharedMutex<TestData> = GlobalSharedMutex::new();
825 local_global_owner.init(TestData { value: 42, text: "global_shared".to_string() });
826
827 let (lock_addr, data_addr) = local_global_owner.share();
828 assert_ne!(lock_addr, 0);
829 assert_ne!(data_addr, 0);
830
831 let mut mirrored_mutex = SharedMutex::<TestData>::new();
832 unsafe {
833 mirrored_mutex.mirror(lock_addr, data_addr);
834 }
835
836 {
837 let guard = mirrored_mutex.read();
838 assert_eq!(guard.value, 42);
839 assert_eq!(guard.text, "global_shared");
840 }
841 {
842 let mut guard = local_global_owner.lock();
843 guard.value = 123;
844 guard.text = "modified_via_global".to_string();
845 }
846 {
847 let guard = mirrored_mutex.read();
848 assert_eq!(guard.value, 123);
849 assert_eq!(guard.text, "modified_via_global");
850 }
851 {
852 let mut guard = mirrored_mutex.lock();
853 guard.value = 456;
854 guard.text = "modified_via_mirror".to_string();
855 }
856 {
857 let guard = local_global_owner.read();
858 assert_eq!(guard.value, 456);
859 assert_eq!(guard.text, "modified_via_mirror");
860 }
861 }
862
863 #[test]
864 fn g_is_locked_behavior() {
865 let m: GlobalSharedMutex<i32> = GlobalSharedMutex::new();
866 m.init(10);
867
868 assert!(!m.is_locked());
869 let r_guard = m.read();
870 assert!(m.is_locked());
871 drop(r_guard);
872 assert!(!m.is_locked());
873
874 let w_guard = m.lock();
875 assert!(m.is_locked());
876 drop(w_guard);
877 assert!(!m.is_locked());
878 }
879
880 #[test]
882 fn g_init_concurrent_access_waits() {
883 let mutex: Arc<GlobalSharedMutex<i32>> = Arc::new(GlobalSharedMutex::new());
884 let barrier = Arc::new(std::sync::Barrier::new(2));
885
886 let mutex_clone1 = Arc::clone(&mutex);
887 let barrier_clone1 = Arc::clone(&barrier);
888 let thread1 = thread::spawn(move || {
889 barrier_clone1.wait();
890 mutex_clone1.init(123); assert_eq!(*mutex_clone1.read(), 123);
892 });
893
894 let mutex_clone2 = Arc::clone(&mutex);
895 let barrier_clone2 = Arc::clone(&barrier);
896 let thread2 = thread::spawn(move || {
897 barrier_clone2.wait();
898 let val = *mutex_clone2.read();
902 assert_eq!(val, 123); });
904
905 thread1.join().unwrap();
906 thread2.join().unwrap();
907 }
908}
909