tokio 读写锁死锁例子

一个简单的 tokio rw 锁 死锁例子:

use std::sync::Arc;
use tokio::{
    self,
    runtime::Runtime,
    sync,
    time::{self, Duration},
};
fn main() {
    let rt = Runtime::new().unwrap();
    rt.block_on(async {
        let rwlock = Arc::new(sync::RwLock::new(0));
        let lock1 = rwlock.clone();
        tokio::spawn(async move {
            let _read1 = lock1.read().await;
            time::sleep(Duration::from_secs(2)).await;
            let _read2 = lock1.read().await;
        });
        time::sleep(Duration::from_secs(1)).await;
        let mut write1 = rwlock.write().await;
        *write1 = 2;
    });
    println!("task done .");
    std::process::exit(-1);
}

简单说一下代码的执行过程。

第14行获取读取锁,然后子任务休眠2秒。

代码跳出子任务,执行18行的休眠1秒。

休眠结束,19行获取写入锁。

两秒结束,16行再次尝试获取读取锁。

 

第14行是首次获取读取锁,此时肯定是可以成功获取的。_read1 持有读取锁,并未释放。

19行获取写入锁,但是因为14行获取的读取锁还未释放。获取失败,等待中。

16行获取读取锁,但是19行还在等待14行的读取锁释放。

此时陷入死锁。

 

为了尽量避免死锁的出现。我们应该在每次使用完锁之后尽快的释放它。比如:

use std::sync::Arc;
use tokio::{
    self,
    runtime::Runtime,
    sync,
    time::{self, Duration},
};
fn main() {
    let rt = Runtime::new().unwrap();
    rt.block_on(async {
        let rwlock = Arc::new(sync::RwLock::new(0));
        let lock1 = rwlock.clone();
        tokio::spawn(async move {
            let read1 = lock1.read().await;
            drop(read1);
            time::sleep(Duration::from_secs(2)).await;
            let read2 = lock1.read().await;
            drop(read2);
        });
        time::sleep(Duration::from_secs(1)).await;
        let mut write1 = rwlock.write().await;
        *write1 = 2;
        drop(write1);
    });
    println!("task done .");
    std::process::exit(-1);
}

 

tokio

Rust官网

Rust 中文社区

posted @ 2022-07-27 16:13  贤云曳贺  阅读(358)  评论(0编辑  收藏  举报