Once with sync_writes and async causes deadlocks in tokio.
Lesny opened this issue · 0 comments
Lesny commented
the following code will freeze:
use cached::proc_macro::once;
use std::time::Duration;
use tokio::time::sleep;
#[once(time = 1, sync_writes = true)]
async fn once_writes_per_second() -> String {
"results".to_string()
}
async fn sleep_secs(secs: u64) {
sleep(Duration::from_secs(secs)).await;
}
#[tokio::main]
async fn main() {
let _ = once_writes_per_second().await;
println!("sleeping for 2 seconds");
sleep_secs(2).await;
let _ = once_writes_per_second().await; // will freeze
println!("executed");
}
it freezes because it will expand to (I redacted the unimportant parts with ...):
async fn once_writes_per_second() -> String {
...
let mut cached = ONCE_WRITES_PER_SECOND.write().await;
if let Some(result) = &*cached {
{
let mut cached = ONCE_WRITES_PER_SECOND.read().await;
...
}
}
...
*cached = Some((now, result.clone()));
result
}
and ONCE_WRITES_PER_SECOND is tokio::sync::RwLock which is not re-entry, and will not allow for read lock to be obtained while keeping write lock. Besides, if we have write lock there is no need for read lock anyway.