@@ -3,8 +3,8 @@ use rand::Rng;
33use crate :: sync:: atomic:: { AtomicUsize , Ordering } ;
44use crate :: sync:: mpsc:: channel;
55use crate :: sync:: {
6- Arc , Barrier , MappedRwLockReadGuard , MappedRwLockWriteGuard , RwLock , RwLockReadGuard ,
7- RwLockWriteGuard , TryLockError ,
6+ Arc , MappedRwLockReadGuard , MappedRwLockWriteGuard , RwLock , RwLockReadGuard , RwLockWriteGuard ,
7+ TryLockError ,
88} ;
99use crate :: thread;
1010
@@ -511,57 +511,42 @@ fn test_downgrade_basic() {
511511}
512512
513513#[ test]
514- fn test_downgrade_readers ( ) {
515- // This test creates 1 writing thread and `R` reader threads doing `N` iterations.
516- const R : usize = 10 ;
517- const N : usize = if cfg ! ( target_pointer_width = "64" ) { 100 } else { 20 } ;
514+ fn test_downgrade_observe ( ) {
515+ // Taken from the test `test_rwlock_downgrade` from:
516+ // https://github.com/Amanieu/parking_lot/blob/master/src/rwlock.rs
518517
519- // The writer thread will constantly update the value inside the `RwLock`, and this test will
520- // only pass if every reader observes all values between 0 and `N`.
521- let rwlock = Arc :: new ( RwLock :: new ( 0 ) ) ;
522- let barrier = Arc :: new ( Barrier :: new ( R + 1 ) ) ;
523-
524- // Create the writing thread.
525- let r_writer = rwlock. clone ( ) ;
526- let b_writer = barrier. clone ( ) ;
527- thread:: spawn ( move || {
528- for i in 0 ..N {
529- let mut write_guard = r_writer. write ( ) . unwrap ( ) ;
530- * write_guard = i;
518+ const W : usize = if cfg ! ( target_pointer_width = "64" ) { 100 } else { 20 } ;
519+ const N : usize = 100 ;
531520
532- let read_guard = RwLockWriteGuard :: downgrade ( write_guard ) ;
533- assert_eq ! ( * read_guard , i ) ;
521+ // This test spawns `W` writer threads, where each will increment a counter `N` times, ensuring
522+ // that the value they wrote has not changed after downgrading.
534523
535- // Wait for all readers to observe the new value.
536- b_writer. wait ( ) ;
537- }
538- } ) ;
524+ let rw = Arc :: new ( RwLock :: new ( 0 ) ) ;
539525
540- for _ in 0 ..R {
541- let rwlock = rwlock. clone ( ) ;
542- let barrier = barrier. clone ( ) ;
543- thread:: spawn ( move || {
544- // Every reader thread needs to observe every value up to `N`.
545- for i in 0 ..N {
546- let read_guard = rwlock. read ( ) . unwrap ( ) ;
547- assert_eq ! ( * read_guard, i) ;
548- drop ( read_guard) ;
549-
550- // Wait for everyone to read and for the writer to change the value again.
551- barrier. wait ( ) ;
552-
553- // Spin until the writer has changed the value.
554- loop {
555- let read_guard = rwlock. read ( ) . unwrap ( ) ;
556- assert ! ( * read_guard >= i) ;
557-
558- if * read_guard > i {
559- break ;
560- }
526+ // Spawn the writers that will do `W * N` operations and checks.
527+ let handles: Vec < _ > = ( 0 ..W )
528+ . map ( |_| {
529+ let rw = rw. clone ( ) ;
530+ thread:: spawn ( move || {
531+ for _ in 0 ..N {
532+ // Increment the counter.
533+ let mut write_guard = rw. write ( ) . unwrap ( ) ;
534+ * write_guard += 1 ;
535+ let cur_val = * write_guard;
536+
537+ // Downgrade the lock to read mode, where the value protected cannot be modified.
538+ let read_guard = RwLockWriteGuard :: downgrade ( write_guard) ;
539+ assert_eq ! ( cur_val, * read_guard) ;
561540 }
562- }
563- } ) ;
541+ } )
542+ } )
543+ . collect ( ) ;
544+
545+ for handle in handles {
546+ handle. join ( ) . unwrap ( ) ;
564547 }
548+
549+ assert_eq ! ( * rw. read( ) . unwrap( ) , W * N ) ;
565550}
566551
567552#[ test]
0 commit comments