|
1 | 1 | use crate::sync::atomic::{AtomicUsize, Ordering};
|
2 | 2 | use crate::sync::mpsc::channel;
|
3 | 3 | use crate::sync::{
|
4 |
| - Arc, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard, |
5 |
| - TryLockError, |
| 4 | + Arc, Barrier, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, |
| 5 | + RwLockWriteGuard, TryLockError, |
6 | 6 | };
|
7 | 7 | use crate::thread;
|
8 | 8 | use rand::Rng;
|
@@ -504,3 +504,81 @@ fn test_downgrade_basic() {
|
504 | 504 | let write_guard = r.write().unwrap();
|
505 | 505 | let _read_guard = RwLockWriteGuard::downgrade(write_guard);
|
506 | 506 | }
|
| 507 | + |
| 508 | +#[test] |
| 509 | +fn test_downgrade_frob() { |
| 510 | + const N: u32 = 10; |
| 511 | + const M: usize = if cfg!(miri) { 100 } else { 1000 }; |
| 512 | + |
| 513 | + let r = Arc::new(RwLock::new(())); |
| 514 | + |
| 515 | + let (tx, rx) = channel::<()>(); |
| 516 | + for _ in 0..N { |
| 517 | + let tx = tx.clone(); |
| 518 | + let r = r.clone(); |
| 519 | + thread::spawn(move || { |
| 520 | + let mut rng = crate::test_helpers::test_rng(); |
| 521 | + for _ in 0..M { |
| 522 | + if rng.gen_bool(1.0 / (N as f64)) { |
| 523 | + drop(RwLockWriteGuard::downgrade(r.write().unwrap())); |
| 524 | + } else { |
| 525 | + drop(r.read().unwrap()); |
| 526 | + } |
| 527 | + } |
| 528 | + drop(tx); |
| 529 | + }); |
| 530 | + } |
| 531 | + drop(tx); |
| 532 | + let _ = rx.recv(); |
| 533 | +} |
| 534 | + |
| 535 | +#[test] |
| 536 | +fn test_downgrade_readers() { |
| 537 | + const R: usize = 16; |
| 538 | + const N: usize = 1000; |
| 539 | + |
| 540 | + let r = Arc::new(RwLock::new(0)); |
| 541 | + let b = Arc::new(Barrier::new(R + 1)); |
| 542 | + |
| 543 | + // Create the writing thread. |
| 544 | + let r_writer = r.clone(); |
| 545 | + let b_writer = b.clone(); |
| 546 | + thread::spawn(move || { |
| 547 | + for i in 0..N { |
| 548 | + let mut write_guard = r_writer.write().unwrap(); |
| 549 | + *write_guard = i; |
| 550 | + |
| 551 | + let read_guard = RwLockWriteGuard::downgrade(write_guard); |
| 552 | + assert_eq!(*read_guard, i); |
| 553 | + |
| 554 | + // Wait for all readers to observe the new value. |
| 555 | + b_writer.wait(); |
| 556 | + } |
| 557 | + }); |
| 558 | + |
| 559 | + for _ in 0..R { |
| 560 | + let r = r.clone(); |
| 561 | + let b = b.clone(); |
| 562 | + thread::spawn(move || { |
| 563 | + // Every reader thread needs to observe every value up to `N`. |
| 564 | + for i in 0..N { |
| 565 | + let read_guard = r.read().unwrap(); |
| 566 | + assert_eq!(*read_guard, i); |
| 567 | + drop(read_guard); |
| 568 | + |
| 569 | + // Wait for everyone to read and for the writer to change the value again. |
| 570 | + b.wait(); |
| 571 | + // Spin until the writer has changed the value. |
| 572 | + |
| 573 | + loop { |
| 574 | + let read_guard = r.read().unwrap(); |
| 575 | + assert!(*read_guard >= i); |
| 576 | + |
| 577 | + if *read_guard > i { |
| 578 | + break; |
| 579 | + } |
| 580 | + } |
| 581 | + } |
| 582 | + }); |
| 583 | + } |
| 584 | +} |
0 commit comments