I have identified a reentrant deadlock issue with read locks. When a read lock needs to be reentered and another thread attempts to acquire a write lock during the outer read lock holding, it leads to a deadlock. The code illustrating this problem is as follows:
fn main() {
let lock = Arc::new(RwLock::new(1));
let new_lock = lock.clone();
std::thread::spawn(move || {
for _ in 0..100 {
println!("write");
let a = new_lock.write().unwrap(); // #1
println!("write ok");
}
});
let outer = lock.read().unwrap();
for _ in 0..100 {
println!("read");
let inner = lock.read().unwrap(); // #2
println!("read ok");
}
drop(outer);
println!("{lock:?}");
}
Running the above program results in a deadlock. After inspecting the implementation of RwLock, I found that it prioritizes write waiters over read waiters. Consequently, when attempting to acquire a write lock at #1 while holding a read lock, it waits. Subsequently, at #2, attempting to acquire a read lock also waits due to the presence of a waiting write lock. As a result, the outer read lock is never released, causing a deadlock.
I would like to understand the rationale behind prioritizing write waiters over read waiters. I have tested similar scenarios in C and Go without encountering this issue. Could this be considered a "bug"?