gpt4 book ai didi

asynchronous - 为什么在使用带有 std::sync::Mutex 的 Tokio 时会出现死锁?

转载 作者:行者123 更新时间:2023-12-03 11:26:29 27 4
gpt4 key购买 nike

我在使用 Tokio 时偶然发现了一个死锁情况:

use tokio::time::{delay_for, Duration};
use std::sync::Mutex;

#[tokio::main]
async fn main() {
let mtx = Mutex::new(0);

tokio::join!(work(&mtx), work(&mtx));

println!("{}", *mtx.lock().unwrap());
}

async fn work(mtx: &Mutex<i32>) {
println!("lock");
{
let mut v = mtx.lock().unwrap();
println!("locked");
// slow redis network request
delay_for(Duration::from_millis(100)).await;
*v += 1;
}
println!("unlock")
}
产生以下输出,然后永远挂起。
lock
locked
lock
根据 to the Tokio docs , 使用 std::sync::Mutex没问题:

Contrary to popular belief, it is ok and often preferred to use the ordinary Mutex from the standard library in asynchronous code.


但是,替换 Mutextokio::sync::Mutex不会触发死锁,一切都“按预期”工作, 但仅限于上面列出的示例案例 .在实际场景中,延迟是由某些 Redis 请求引起的,它仍然会失败。
我认为这可能是因为我实际上根本没有产生线程,因此,即使“并行”执行,我也会锁定同一个线程,因为 await 只会产生执行。
在不产生单独线程的情况下实现我想要的 Rustacean 方法是什么?

最佳答案

原因是不行 使用 std::sync::Mutex这是你拿着它穿过 .await观点。在这种情况下:

  • 任务 1 持有互斥锁,但在 delay_for 上被暂停.
  • 任务 2 被调度并运行,但无法获取互斥锁,因为它仍然属于任务 1。它将在获取互斥锁时同步阻塞。

  • 由于任务 2 被阻塞,这也意味着运行时线程被完全阻塞。它实际上无法进入其计时器处理状态(当运行时空闲且不处理用户任务时会发生这种情况),因此无法恢复任务 1。
    因此,您现在正在观察一个僵局。
    ==> 如果您需要在 .await 上持有互斥锁点你必须使用异步互斥锁。正如 tokio 文档所描述的,同步互斥体可以与异步程序一起使用 - 但它们可能无法跨 .await 保存。点。

    关于asynchronous - 为什么在使用带有 std::sync::Mutex 的 Tokio 时会出现死锁?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/63712823/

    27 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com