根据哪条规则,Rust编译器确保锁被释放?

8nuwlpux  于 2023-06-23  发布在  其他
关注(0)|答案(2)|浏览(198)

我试图理解Rust的Mutex的行为,使用小片段。我对RAII有一个合理的想法,MutexGuard扮演的角色,我知道lock()正在阻止呼叫。
下面的代码(Snippet1)起作用:

use std::sync::Mutex;

fn main() {
    let a_mutex = Mutex::new(5);
    let v = a_mutex.lock().unwrap().to_string();

    // An attempt to acquire the lock again.
    let w = a_mutex.try_lock().unwrap();
}

但是这段代码(Snippet2)不起作用!

use std::sync::Mutex;

fn main() {
    let a_mutex = Mutex::new(5);
    let v = a_mutex.lock().unwrap();

    // An attempt to acquire the lock again.
    let w = a_mutex.try_lock().unwrap();
}

输出可以预见地告诉我再次获取锁的尝试不会成功(WouldBlock;从我Unix/C编程的日子里,我对EWOULDBLOCK表示什么有一个很好的概念)。

Finished dev [unoptimized + debuginfo] target(s) in 2.29s
     Running `target/debug/playground`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "WouldBlock"', src/main.rs:19:32
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

这(Snippet3)告诉我们-毫不奇怪-锁没有释放的时间,我们正在尝试再次获取它:

use std::sync::Mutex;

fn main() {
    let a_mutex = Mutex::new(5);

    let v = a_mutex.lock().unwrap();
    println!("v = {:?}", v.to_string());
    
    let w = a_mutex.try_lock().unwrap();
}

输出说明了一切:

Finished dev [unoptimized + debuginfo] target(s) in 0.60s
     Running `target/debug/playground`
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: "WouldBlock"', src/main.rs:19:32
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

v = "5"

我理解这种行为与范围规则、临时性和表达式有关。
可以与 { Place| Value } Contexts 也是,但我不确定这部分。
但是我无法向自己解释,哪条规则决定了Snippets 1/2/3的行为之间的差异。特别是:

let v = a_mutex.lock().unwrap().to_string();

和/或

let v = a_mutex.lock().unwrap();

两者都是表达式,但在第一种情况下释放了MutexGuard。我错过了什么?
我已经经历了this,和这个,但这些都没能让我看到光明。
期待着一两个小动作,这使我的理解更加清晰。
TIA。

py49o6xq

py49o6xq1#

在第一个代码段中,锁保护是一个临时变量,在语句的末尾被删除,而在第二个和第三个代码段中,它是一个普通变量,在作用域的末尾被删除。
当你执行let v = a_mutex.lock().unwrap();时,你将MutexGuard赋给一个变量。与所有变量一样,它在作用域末尾删除,try_lock()之后。
但是,当您在其上调用to_string()时,锁并不存储在任何地方--只有字符串存储在变量中。因此,锁是临时的。有时候,当出现在let语句中时,临时变量会被扩展到作用域的末尾,但当这是一个方法调用(temporary.method())时,临时变量不会被扩展,而是在语句末尾try_lock()调用之前被删除。

zqdjd7g9

zqdjd7g92#

这可能有助于澄清ChayimFriedman的答案

use std::sync::Mutex;

fn main() {
    let a_mutex = Mutex::new(5);

    {
        let v = a_mutex.lock().unwrap();
    }
    // v is droped at this moment

    // An attempt to acquire the lock again.
    let w = a_mutex.try_lock().unwrap();
}

当你这样做的时候

use std::sync::Mutex;

fn main() {
    let a_mutex = Mutex::new(5);
    let v = a_mutex.lock().unwrap();

    // An attempt to acquire the lock again.
    // v is still valid and you can't lock it again.
    let w = a_mutex.try_lock().unwrap();
}

相关问题