我试图理解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。
2条答案
按热度按时间py49o6xq1#
在第一个代码段中,锁保护是一个临时变量,在语句的末尾被删除,而在第二个和第三个代码段中,它是一个普通变量,在作用域的末尾被删除。
当你执行
let v = a_mutex.lock().unwrap();
时,你将MutexGuard
赋给一个变量。与所有变量一样,它在作用域末尾删除,try_lock()
之后。但是,当您在其上调用
to_string()
时,锁并不存储在任何地方--只有字符串存储在变量中。因此,锁是临时的。有时候,当出现在let
语句中时,临时变量会被扩展到作用域的末尾,但当这是一个方法调用(temporary.method()
)时,临时变量不会被扩展,而是在语句末尾try_lock()
调用之前被删除。zqdjd7g92#
这可能有助于澄清ChayimFriedman的答案
当你这样做的时候