在代码中

fn do_something_under_lock(some_bool_mutex: &Mutex<bool>) {
    do_something_before_lock();

    let some_bool = some_bool_mutex.lock().unwrap();
    do_something_with_some_bool(some_bool);

    do_something_after_lock();
}

锁定会在do_something_after_lock();之后才释放吗?(或者也许编译器可以证明我们不需要很长的锁定时间并减少它?)

如果只有在do_something_after_lock();之后才会释放锁,我们可以通过将lock()包装到自己的作用域中来更早地释放锁吗,比如

fn do_something_under_lock_in_scope(some_bool_mutex: &Mutex<bool>) {
    do_something_before_lock();

    {
        let some_bool = some_bool_mutex.lock().unwrap();
        do_something_with_some_bool(some_bool);
    }

    do_something_after_lock();
}

包装到作用域是告诉编译器我们想要什么的最好方式,还是我们应该使用其他方式,比如drop或其他什么?

推荐答案

锁将在do_something_after_lock()之后被释放.这被认为是可观察的行为,因此,不允许编译器更改这一点.

将锁放在作用域中和使用drop()都可以.我更喜欢drop()版本,但这是主观的.然而,需要注意的一件事是,在异步函数中,即使您将锁drop()次(它将被释放,但编译器仍会将其类型视为生成器类型的一部分),锁也被视为活动的,因此,如果锁不能跨.await点持有(例如,因为它不是Send点),则必须使用块,drop()是不够的.例如,以下代码出错:

async fn foo(mutex: &Mutex<i32>) {
    let _guard = mutex.lock().unwrap();
    drop(_guard);
    
    tokio::time::sleep(Duration::from_secs(1)).await;
}

tokio::spawn(foo(mutex));

您需要使用块:

async fn foo(mutex: &Mutex<i32>) {
    {
        let _guard = mutex.lock().unwrap();
    }
    
    tokio::time::sleep(Duration::from_secs(1)).await;
}

tokio::spawn(foo(mutex));

This is expected to improve in future Rust versions.

Rust相关问答推荐

如何在不安全的代码中初始化枚举 struct

如何从polars DataFrame中获取一个列作为Option String?<>

将内部类型作为参数的泛型 struct 上的方法

如何处理动态 struct 实例化?

为什么Rust函数的移植速度比C++慢2倍?

如何导入crate-type=[";cdylib;]库?

在rust sqlx中使用ilike和push bind

无符号整数的Rust带符号差

Rust编译器似乎被结果类型与anyhow混淆

为什么HashMap::get和HashMap::entry使用不同类型的密钥?

Rust FFI 和 CUDA C 性能差异

返回优化后的标题:返回异步块的闭包的类型擦除

pyO3 和 Panics

为什么 Rust 的临时值有时有参考性有时没有?

在给定 Rust 谓词的情况下,将 Some 转换为 None 的惯用方法是什么?

如何将 Rust 中的树状 struct 展平为 Vec<&mut ...>?

火箭整流罩、tokio-scheduler 和 cron 的生命周期问题

在 Rust 中枚举字符串的最佳方式? (字符()与 as_bytes())

使用 rust-sqlx/tokio 时如何取消长时间运行的查询

为什么-x试图解析为文字并在声明性宏中失败?