instance_copy_on_write/cow_mutex.rs
1/*-
2 * instance-copy-on-write - a synchronization primitive based on copy-on-write.
3 *
4 * Copyright (C) 2025 Aleksandr Morozov alex@
5 *
6 * The scram-rs crate can be redistributed and/or modified
7 * under the terms of either of the following licenses:
8 *
9 * 1. the Mozilla Public License Version 2.0 (the “MPL”) OR
10 *
11 * 2. EUROPEAN UNION PUBLIC LICENCE v. 1.2 EUPL © the European Union 2007, 2016
12 */
13
14#[cfg(test)]
15use std::sync::Weak;
16use std::{fmt, ops::{Deref, DerefMut}, sync::{Arc, RwLock, RwLockWriteGuard, TryLockError}};
17
18use crossbeam_utils::Backoff;
19
20use crate::{ICoWError, ICoWLockTypes};
21
22
23/// A read only guard. Implements [Deref] only. The guarded value is valid
24/// all the time, even if the inner value was updated. The updated value
25/// will not be visible in the current instance until `re-read` is
26/// performed.
27#[derive(Debug)]
28pub struct ICoWRead<'read, ITEM: fmt::Debug + Send>
29{
30 /// Guarded value.
31 item: Arc<ITEM>,
32
33 /// A bind to base.
34 bind: &'read ICoW<ITEM>
35}
36
37#[cfg(test)]
38impl<'read, ITEM: fmt::Debug + Send> ICoWRead<'read, ITEM>
39{
40 fn weak(&self) -> Weak<ITEM>
41 {
42 return Arc::downgrade(&self.item);
43 }
44}
45
46impl<'read, ITEM: fmt::Debug + Send> Deref for ICoWRead<'read, ITEM>
47{
48 type Target = ITEM;
49
50 fn deref(&self) -> &Self::Target
51 {
52 return &self.item;
53 }
54}
55
56
57/// A write-guard which holds new value to which the new values are written. And
58/// previous value too. This type of guard is not exclusive, so it does not prevent
59/// multiple CoW operations. Normally, if some object which may be written
60/// simultaniously i.e lost connection to remote server and reconnect is required,
61/// the `exclusive` lock would be more desirable.
62#[derive(Debug)]
63pub struct ICoWCopy<'copy, ITEM: fmt::Debug + Send>
64{
65 /// A reference to previous value
66 prev_item: ICoWRead<'copy, ITEM>,
67
68 /// A freshly createc/copied/clonned item
69 new_item: ITEM,
70
71 /// A reference to base to avoid Send.
72 inst: &'copy ICoW<ITEM>
73}
74
75impl<'copy, ITEM: fmt::Debug + Send> Deref for ICoWCopy<'copy, ITEM>
76{
77 type Target = ITEM;
78
79 fn deref(&self) -> &Self::Target
80 {
81 return &self.new_item;
82 }
83}
84
85impl<'copy, ITEM: fmt::Debug + Send> DerefMut for ICoWCopy<'copy, ITEM>
86{
87 fn deref_mut(&mut self) -> &mut Self::Target
88 {
89 return &mut self.new_item
90 }
91}
92
93impl<'copy, ITEM: fmt::Debug + Send> ICoWCopy<'copy, ITEM>
94{
95 /// Returns a reference to previous value. To access modified version use
96 /// [Deref] or [DerefMut].
97 pub
98 fn prev_val(&self) -> &ITEM
99 {
100 return &self.prev_item;
101 }
102
103 /// Commits the changes made in the guarded variable. A non-blocking
104 /// function. It will not block the thread completly and returns the
105 /// [ICoWError::WouldBlock] if attempt to grab the pointer atomically
106 /// fails.
107 ///
108 /// # Returns
109 ///
110 /// The [Result::Err] is returned with:
111 ///
112 /// * `0` - [ICoWError] with the error type.
113 ///
114 /// * `1` - [ICoWCopy] instance itself.
115 ///
116 /// Error types [ICoWError]:
117 ///
118 /// * [ICoWError::ExclusiveLockPending] - if exclusivly locked from another thread.
119 ///
120 /// * [ICoWError::WouldBlock] - if "exponential backoff has completed and blocking the thread is advised".
121 pub
122 fn commit(self) -> Result<(), (ICoWError, Self)>
123 {
124 let write_lock =
125 self
126 .inst
127 .inner
128 .try_write();
129 //.unwrap_or_else(|e| e.into_inner());
130
131 let mut lock =
132 match write_lock
133 {
134 Ok(lock) =>
135 lock,
136 Err(TryLockError::Poisoned(lock_err)) =>
137 lock_err.into_inner(),
138 Err(TryLockError::WouldBlock) =>
139 return Err((ICoWError::ExclusiveLockPending, self)),
140 };
141
142 *lock = Arc::new(self.new_item);
143
144 return Ok(());
145 }
146
147}
148
149/// A write-guard which holds new value to which the new values are written. And
150/// previous value too. This type of guard is exclusive, so multiple
151/// CoW operations **CANNOT** be performed in parallel which is good for instance
152/// update without racing. The readers are also waiting until the changes are
153/// commited.
154#[derive(Debug)]
155pub struct ICoWLock<'lock, ITEM: fmt::Debug + Send>
156{
157 /// An exclusive lock in the previous value.
158 prev_item: RwLockWriteGuard<'lock, Arc<ITEM>>,
159
160 /// A freshly createc/copied/clonned item
161 item: ITEM,
162
163 /// A reference to base to avoid Send.
164 inst: &'lock ICoW<ITEM>
165}
166
167impl<'lock, ITEM: fmt::Debug + Send> ICoWLock<'lock, ITEM>
168{
169 /// Returns a reference to previous value. To access modified version use
170 /// [Deref] or [DerefMut].
171 pub
172 fn prev_val(&self) -> &ITEM
173 {
174 return self.prev_item.as_ref();
175 }
176
177 /// Commits the changes made in the guarded variable.
178 ///
179 /// # Returns
180 ///
181 /// Always returns [Result::Ok], but the `atomic` realization
182 /// would return [Result::Err] if:
183 ///
184 /// > The [Result::Err] is retruned if race condition happens i.e when
185 /// > updating the inner atomic ptr fails because someone have already
186 /// > changed the value.
187 #[inline]
188 pub
189 fn commit(mut self) -> Result<(), Self>
190 {
191 *self.prev_item = Arc::new(self.item);
192
193 return Ok(());
194 }
195}
196
197impl<'lock, ITEM: fmt::Debug + Send> Deref for ICoWLock<'lock, ITEM>
198{
199 type Target = ITEM;
200
201 fn deref(&self) -> &Self::Target
202 {
203 return &self.item;
204 }
205}
206
207impl<'lock, ITEM: fmt::Debug + Send> DerefMut for ICoWLock<'lock, ITEM>
208{
209 fn deref_mut(&mut self) -> &mut Self::Target
210 {
211 return &mut self.item
212 }
213}
214
215/// A main structure which implements CoW approach based on [RwLock] for the
216/// multithreading syncing. The object stored inside can be read directly, but
217/// modifying the `inner` value is performed using `CoW` copy-on-write approach.
218///
219/// The inner value must either [Copy], [Clone], [Default], or provide
220/// new value manually. The copied value is modified and stored back either
221/// shared or exclusive method. The exclusive lock prevents other CoW operations
222/// guaranteeing the uniq write access.
223///
224/// ```ignore
225/// #[derive(Debug, Clone)]
226/// struct TestStruct { s: u32 }
227///
228/// let cow_val = ICoW::new(TestStruct{ s: 2 });
229///
230/// // read
231/// let read0 = cow_val.read().unwrap();
232/// // ...
233/// drop(read0);
234///
235/// // write new non-exclusivly
236/// let mut write0 = cow_val.try_clone().unwrap();
237/// write0.s = 3;
238///
239/// write0.commit().unwrap();
240///
241/// // write new exclusivly
242/// let mut write0 = cow_val.try_clone_exclusivly().unwrap();
243/// write0.s = 3;
244///
245/// write0.commit().unwrap();
246///
247/// ```
248#[derive(Debug)]
249pub struct ICoW<ITEM: fmt::Debug + Send>
250{
251 /// A rwlock protected CoW.
252 inner: RwLock<Arc<ITEM>>
253}
254
255impl<ITEM: fmt::Debug + Send> ICoW<ITEM>
256{
257 /// Initalizes a new instance.
258 pub
259 fn new(item: ITEM) -> Self
260 {
261 return Self{ inner: RwLock::new(Arc::new(item))}
262 }
263
264 /// Returns the syncing meachanism.
265 pub
266 fn get_lock_type() -> ICoWLockTypes
267 {
268 return ICoWLockTypes::RwLock;
269 }
270}
271
272impl<ITEM: fmt::Debug + Send> ICoW<ITEM>
273{
274 /// Attempts to read the inner value returning the guard. This function
275 /// blocks the current thread until the value becomes available. This
276 /// can happen if exclusive copy-on-write is in progress.
277 ///
278 /// # Returns
279 ///
280 /// An instance with clonned reference is returned.
281 pub
282 fn read(&self) -> ICoWRead<'_, ITEM>
283 {
284 let lock =
285 self
286 .inner
287 .read()
288 .unwrap_or_else(|e| e.into_inner());
289
290 return ICoWRead{ item: lock.clone(), bind: self };
291 }
292
293 /// Attempts to read the inner value, returning the read guard in case of success.
294 /// This function does not block the current thread until the value becomes available.
295 /// This function fails if exclusive copy-on-write is in progress.
296 ///
297 /// But, this fucntion would block the thread until the [Backoff] reports
298 /// that it is recomended to park the thread.
299 ///
300 /// # Returns
301 ///
302 /// A [Option] is retrurned. The [Option::None] is returned if operation
303 /// would block for a long time.
304 pub
305 fn try_read(&self) -> Option<ICoWRead<'_, ITEM>>
306 {
307 let lock_res =
308 self
309 .inner
310 .try_read();
311
312 match lock_res
313 {
314 Ok(lock) =>
315 {
316 return Some(ICoWRead{ item: lock.clone(), bind: self });
317 },
318 Err(TryLockError::WouldBlock)=>
319 {
320 return None;
321 },
322 Err(TryLockError::Poisoned(lock)) =>
323 {
324 return Some(ICoWRead{ item: lock.into_inner().clone(), bind: self });
325 }
326 }
327 }
328
329 /// Attempts to grab the **exclusive** Copy-on-Write to prevent duplicate
330 /// writing.
331 ///
332 /// Non-blocking function i.e returns if it fails to acquire the
333 /// clone before some deadline.
334 ///
335 /// # Returns
336 ///
337 /// An [Option] is returned where the [Option::None] is returned if
338 /// an exclusive CoW lock have already been issued.
339 pub
340 fn try_new_exclusivly(&self, new_item: ITEM) -> Option<ICoWLock<'_, ITEM>>
341 {
342 let write_lock =
343 match self.inner.try_write()
344 {
345 Ok(r) => r,
346 Err(TryLockError::Poisoned(e)) => e.into_inner(),
347 Err(TryLockError::WouldBlock) =>
348 return None
349 };
350
351 return Some(
352 ICoWLock{ prev_item: write_lock, item: new_item, inst: self }
353 );
354 }
355
356 /// Attempts to update old value to new value for the inner.
357 ///
358 /// Non-blocking function i.e returns if it fails to acquire the
359 /// clone before some deadline. And does not block if the write access
360 /// is not available now due to the exclusive lock pending.
361 ///
362 /// Does not return guard. Updates the value in-place.
363 ///
364 /// # Returns
365 ///
366 /// A [Result] is returned where the [Result::Err] is returned with:
367 ///
368 /// * [ICoWError::ExclusiveLockPending] - if exclsive write already pending.
369 ///
370 /// * errors which are returned by [ICoWCopy::commit()].
371 pub
372 fn try_new_inplace(&self, new_item: ITEM) -> Result<(), (ICoWError, ITEM)>
373 {
374 if let Some(read) = self.try_read()
375 {
376 let ret =
377 ICoWCopy
378 {
379 prev_item: read,
380 new_item: new_item,
381 inst: self
382 };
383
384 return ret.commit().map_err(|e| (e.0, e.1.new_item));
385 }
386 else
387 {
388 return Err((ICoWError::WouldBlock, new_item));
389 }
390 }
391
392 /// Attempts to update old value to new value for the inner
393 /// **exclusively**.
394 ///
395 /// Non-blocking function i.e returns if it fails to acquire the
396 /// clone before some deadline.
397 ///
398 /// Does not return guard. Updates the value in-place.
399 ///
400 /// # Returns
401 ///
402 /// A [Result] is returned where the [Result::Err] is returned with:
403 ///
404 /// * [ICoWError::ExclusiveLockPending] - if exclsive write already pending.
405 ///
406 /// * [ICoWError::AlreadyUpdated] - if duplicate write operation attempt.
407 ///
408 /// * [ICoWError::RaceCondition] - a race condition detected during update.
409 ///
410 /// * errors which are returned by [ICoWCopy::commit()].
411 pub
412 fn try_new_exclusivly_inplace(&self, new_item: ITEM) -> Result<(), (ICoWError, ITEM)>
413 {
414
415 let write_lock =
416 match self.inner.try_write()
417 {
418 Ok(lock) =>
419 lock,
420 Err(TryLockError::Poisoned(e)) =>
421 e.into_inner(),
422 Err(TryLockError::WouldBlock) =>
423 return Err((ICoWError::ExclusiveLockPending, new_item))
424 };
425
426 let ret =
427 ICoWLock{ prev_item: write_lock, item: new_item, inst: self };
428
429 return Ok(ret.commit().unwrap());
430 }
431}
432
433impl<ITEM: fmt::Debug + Send + Copy> ICoW<ITEM>
434{
435 /// Attempts to perform the copy of the inner value for writing.
436 ///
437 /// Non-blocking function i.e returns if it fails to acquire the
438 /// copy before some deadline.
439 ///
440 /// # Returns
441 ///
442 /// An [Option] is returned where the [Option::None] is returned if
443 /// it failed.
444 pub
445 fn try_copy(&self) -> Option<ICoWCopy<'_, ITEM>>
446 {
447 let read = self.try_read()?;
448
449 let new_item = *read.item.as_ref();
450
451 let ret =
452 ICoWCopy
453 {
454 prev_item: read,
455 new_item: new_item,
456 inst: self
457 };
458
459 return Some(ret);
460 }
461
462 /// Attempts to perform the copy of the inner value for
463 /// **exclusive** writing.
464 ///
465 /// Non-blocking function i.e returns if it fails to acquire the
466 /// copy before some deadline.
467 ///
468 /// # Returns
469 ///
470 /// An [Option] is returned where the [Option::None] is returned if
471 /// an exclusive CoW lock have already been issued.
472 pub
473 fn try_copy_exclusivly(&self) -> Option<ICoWLock<'_, ITEM>>
474 {
475
476 let write_lock =
477 match self.inner.try_write()
478 {
479 Ok(r) => r,
480 Err(TryLockError::Poisoned(e)) => e.into_inner(),
481 Err(TryLockError::WouldBlock) =>
482 return None
483 };
484
485 let new_item = *write_lock.as_ref();
486
487 return Some(
488 ICoWLock{ prev_item: write_lock, item: new_item, inst: self }
489 );
490 }
491}
492
493impl<ITEM: fmt::Debug + Send + Clone> ICoW<ITEM>
494{
495 /// Attempts to perform the clone of the inner value for writing.
496 ///
497 /// Non-blocking function i.e returns if it fails to acquire the
498 /// clone before some deadline.
499 ///
500 /// # Returns
501 ///
502 /// An [Option] is returned where the [Option::None] is returned if
503 /// it failed.
504 pub
505 fn try_clone(&self) -> Option<ICoWCopy<'_, ITEM>>
506 {
507 let read = self.try_read()?;
508
509 let new_item = read.item.as_ref().clone();
510
511 let ret =
512 ICoWCopy
513 {
514 prev_item: read,
515 new_item: new_item,
516 inst: self
517 };
518
519 return Some(ret);
520 }
521
522 /// Attempts to perform the clone of the inner value for
523 /// **exclusive** writing.
524 ///
525 /// Non-blocking function i.e returns if it fails to acquire the
526 /// clone before some deadline.
527 ///
528 /// # Returns
529 ///
530 /// An [Option] is returned where the [Option::None] is returned if
531 /// an exclusive CoW lock have already been issued.
532 pub
533 fn try_clone_exclusivly(&self) -> Option<ICoWLock<'_, ITEM>>
534 {
535
536 let write_lock =
537 match self.inner.try_write()
538 {
539 Ok(r) => r,
540 Err(TryLockError::Poisoned(e)) => e.into_inner(),
541 Err(TryLockError::WouldBlock) =>
542 return None
543 };
544
545 let new_item = write_lock.as_ref().clone();
546
547 return Some(
548 ICoWLock{ prev_item: write_lock, item: new_item, inst: self }
549 );
550 }
551}
552
553impl<ITEM: fmt::Debug + Send + Default> ICoW<ITEM>
554{
555 /// Attempts to init default of the inner value for writing.
556 ///
557 /// Non-blocking function i.e returns if it fails to acquire the
558 /// clone before some deadline.
559 ///
560 /// # Returns
561 ///
562 /// An [Option] is returned where the [Option::None] is returned if
563 /// it failed.
564 pub
565 fn try_default(&self) -> Option<ICoWCopy<'_, ITEM>>
566 {
567 let read = self.try_read()?;
568
569 let new_item = ITEM::default();
570
571 let ret =
572 ICoWCopy
573 {
574 prev_item: read,
575 new_item: new_item,
576 inst: self
577 };
578
579 return Some(ret);
580 }
581
582
583 /// Attempts to init default of the inner value for
584 /// **exclusive** writing.
585 ///
586 /// Non-blocking function i.e returns if it fails to acquire the
587 /// clone before some deadline.
588 ///
589 /// # Returns
590 ///
591 /// An [Option] is returned where the [Option::None] is returned if
592 /// an exclusive CoW lock have already been issued.
593 pub
594 fn try_default_exclusivly(&self) -> Option<ICoWLock<'_, ITEM>>
595 {
596 let write_lock =
597 match self.inner.try_write()
598 {
599 Ok(r) => r,
600 Err(TryLockError::Poisoned(e)) => e.into_inner(),
601 Err(TryLockError::WouldBlock) =>
602 return None
603 };
604
605 let new_item = ITEM::default();
606
607 return Some(
608 ICoWLock{ prev_item: write_lock, item: new_item, inst: self }
609 );
610 }
611}
612
613
614#[cfg(test)]
615mod test
616{
617 use std::{sync::{mpsc, LazyLock}, time::{Duration, Instant}};
618
619 use super::*;
620
621
622
623
624 #[test]
625 fn test_3()
626 {
627 #[derive(Debug, Clone)]
628 struct Test { s: String };
629
630 let icow = ICoW::new(Test{ s: "test".into() });
631
632 for _ in 0..10
633 {
634 let s = Instant::now();
635
636 let read0 = icow.read();
637
638 let e = s.elapsed();
639
640 println!("{:?}", e);
641 }
642
643 }
644
645 #[test]
646 fn test_33()
647 {
648 #[derive(Debug, Clone)]
649 struct Test { s: String };
650
651 let icow = ICoW::new(Test{ s: "test".into() });
652
653 let write_ex = icow.try_clone_exclusivly().unwrap();
654
655 {
656 let write_ex_err = icow.try_clone_exclusivly();
657 assert_eq!(write_ex_err.is_none(), true);
658 }
659
660 let write_ex_err = icow.try_clone();
661 assert_eq!(write_ex_err.is_none(), true);
662
663 let read1 = icow.try_read();
664 assert_eq!(read1.is_none(), true);
665
666 drop(write_ex);
667
668 drop(icow);
669
670 }
671
672 #[test]
673 fn test_4()
674 {
675 #[derive(Debug, Clone)]
676 struct Test { s: u32 }
677
678 let icow = ICoW::new(Test{ s: 1 });
679
680 let read0 = icow.read();
681 let read1 = icow.read();
682
683 let mut excl_write = icow.try_clone_exclusivly().unwrap();
684
685 excl_write.item.s = 5;
686
687
688 excl_write.commit().unwrap();
689
690 assert_eq!(read0.item.s, 1);
691
692 let read3 = icow.read();
693 assert_eq!(read3.item.s, 5);
694
695 let mut writing = icow.try_clone().unwrap();
696 writing.s = 4;
697
698 writing.commit().unwrap();
699
700 assert_eq!(read0.item.s, 1);
701 assert_eq!(read3.item.s, 5);
702
703 let read4 = icow.read();
704 assert_eq!(read4.s, 4);
705 }
706
707 #[test]
708 fn test_5()
709 {
710 #[derive(Debug, Clone)]
711 struct Test { s: u32 }
712
713 let icow = Arc::new(ICoW::new(Test{ s: 1 }));
714
715 let read0 = icow.read();
716 let read2 = icow.read();
717
718 let c_icow = icow.clone();
719
720 let (se, rc) = mpsc::channel::<()>();
721 let handler0 =
722 std::thread::spawn(move ||
723 {
724 let mut lock0 = c_icow.try_clone_exclusivly().unwrap();
725
726 se.send(()).unwrap();
727
728 lock0.item.s = 5;
729
730 std::thread::sleep(Duration::from_micros(2));
731
732 lock0.commit().unwrap();
733 }
734 );
735
736 rc.recv().unwrap();
737
738 let s = Instant::now();
739
740 let read1 = icow.read();
741
742 let e = s.elapsed();
743
744 println!("{:?}", e);
745
746
747 assert_eq!(read1.item.s, 5);
748 assert_eq!(read0.item.s, 1);
749
750 handler0.join().unwrap();
751
752 let weak0 = read0.weak();
753 let weak1 = read1.weak();
754
755 drop(read0);
756 drop(read1);
757
758 assert_eq!(weak0.upgrade().is_some(), true);
759 assert_eq!(weak1.upgrade().is_some(), true);
760
761 drop(read2);
762 assert_eq!(weak0.upgrade().is_none(), true);
763 assert_eq!(weak1.upgrade().is_some(), true);
764 }
765
766
767 #[test]
768 fn test_6()
769 {
770 #[derive(Debug, Clone)]
771 struct Test { s: u32 }
772
773 let icow = Arc::new(ICoW::new(Test{ s: 1 }));
774
775 let read0 = icow.read();
776 let read2 = icow.read();
777
778 let c_icow = icow.clone();
779
780 let (se, rc) = mpsc::channel::<()>();
781 let handler0 =
782 std::thread::spawn(move ||
783 {
784 let read2 = c_icow.read();
785
786 let mut lock0 = c_icow.try_clone_exclusivly().unwrap();
787
788 se.send(()).unwrap();
789
790 lock0.item.s = 5;
791
792 std::thread::sleep(Duration::from_nanos(50));
793 lock0.commit().unwrap();
794
795 let read3 = c_icow.read();
796
797 assert_eq!(read2.item.s, 1);
798 assert_eq!(read3.item.s, 5);
799 }
800 );
801
802 rc.recv().unwrap();
803
804 for _ in 0..100000000
805 {
806 let read1 = icow.read();
807
808 if read1.item.s == 1
809 {
810 continue;
811 }
812 else
813 {
814 break;
815 }
816 }
817
818 let read1 = icow.read();
819 assert_eq!(read1.item.s, 5);
820
821 handler0.join().unwrap();
822
823 return;
824 }
825
826
827 #[test]
828 fn test_7()
829 {
830 #[derive(Debug, Clone)]
831 struct TestStruct { s: u32 }
832
833 impl TestStruct
834 {
835 fn new(s: u32) -> Self
836 {
837 return Self{ s: s };
838 }
839 }
840
841 static VAL: LazyLock<ICoW<TestStruct>> =
842 LazyLock::new(|| ICoW::new(TestStruct::new(1)));
843
844
845
846
847 let borrow1 = VAL.read();
848 assert_eq!(borrow1.item.s, 1);
849
850 let (mpsc_send, mpsc_rcv) = mpsc::channel::<u64>();
851 let (mpsc_send2, mpsc_rcv2) = mpsc::channel::<u64>();
852
853 let thread1 =
854 std::thread::spawn(move ||
855 {
856 for _ in 0..1000
857 {
858 let _ = mpsc_rcv2.recv();
859 let borrow1 = VAL.read();
860
861 let mut transaction = VAL.try_clone_exclusivly().unwrap();
862
863 transaction.item.s = 5;
864
865
866
867 std::thread::sleep(Duration::from_nanos(1001));
868 transaction.commit().unwrap();
869
870 let borrow2 = VAL.read();
871
872
873 assert_eq!(borrow1.item.s, 1);
874
875 assert_eq!(borrow2.item.s, 5);
876
877 let _ = mpsc_send.send(1);
878 }
879 }
880 );
881
882
883
884 for x in 0..1000
885 {
886 println!("{}", x);
887 mpsc_send2.send(1).unwrap();
888 let _ = mpsc_rcv.recv();
889
890 let borrow1 = VAL.read();
891 assert_eq!(borrow1.item.s, 5);
892
893 let mut transaction = VAL.try_clone_exclusivly().unwrap();
894 transaction.item.s = 1;
895 transaction.commit().unwrap();
896
897 let borrow1 = VAL.read();
898 assert_eq!(borrow1.item.s, 1);
899
900 }
901
902
903
904 thread1.join().unwrap();
905
906
907 }
908
909
910 #[test]
911 fn test_8()
912 {
913 #[derive(Debug, Clone)]
914 struct Test { s: u32 }
915
916 let icow = Arc::new(ICoW::new(Test{ s: 1 }));
917
918 for _ in 0..20
919 {
920 let read0 = icow.read();
921 let read2 = icow.read();
922
923 let c_icow = icow.clone();
924
925 //let (se, rc) = mpsc::channel::<()>();
926 let handler0 =
927 std::thread::spawn(move ||
928 {
929 let read2 = c_icow.read();
930
931 let mut lock0 = c_icow.try_clone().unwrap();
932
933 //se.send(()).unwrap();
934
935 lock0.s = 5;
936
937 std::thread::sleep(Duration::from_micros(1));
938 lock0.commit().unwrap();
939
940 let read3 = c_icow.read();
941
942 assert_eq!(read2.item.s, 1);
943 assert_eq!(read3.item.s, 5);
944 }
945 );
946
947 //rc.recv().unwrap();
948
949 for i in 0..1000000000
950 {
951 let read1 = icow.read();
952
953 if read1.item.s == 1
954 {
955 continue;
956 }
957 else
958 {
959 println!("{}", i);
960 break;
961 }
962 }
963
964 let read1 = icow.read();
965 assert_eq!(read1.item.s, 5);
966
967 handler0.join().unwrap();
968
969 let mut lock0 = icow.try_clone().unwrap();
970 lock0.s = 1;
971 lock0.commit().unwrap();
972 }
973
974 return;
975 }
976}