我试图使用小片段来理解 Rust 互斥体的行为。我对 RAII 及其所扮演的角色有一个合理的想法,并且我知道阻塞呼叫的MutexGuard事实。lock()
以下代码(代码片段1)有效:
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();
}
Run Code Online (Sandbox Code Playgroud)
但这段代码(代码片段2)不起作用!
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();
}
Run Code Online (Sandbox Code Playgroud)
不出所料,输出告诉我,再次获取锁的尝试不会成功(WouldBlock;从我的 Unix/C 编程时代起,我就很清楚 an 的含义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
Run Code Online (Sandbox Code Playgroud)
不出所料,这个(片段3)告诉我们锁尚未释放,我们正尝试再次获取它:
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();
}
Run Code Online (Sandbox Code Playgroud)
输出说明了一切:
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"
Run Code Online (Sandbox Code Playgroud)
我知道这种行为与范围规则、临时变量和表达式有关。
可能与{ Place |偶数 Value } 上下文也是如此,但我不确定这部分。
但我无法向自己解释,哪些规则决定了 Snippets 1/2/3 行为之间的差异。尤其:
let v = a_mutex.lock().unwrap().to_string();
Run Code Online (Sandbox Code Playgroud)
和
let v = a_mutex.lock().unwrap();
Run Code Online (Sandbox Code Playgroud)
两者都是表达式,但第一种情况是MutexGuard被释放的。我缺少什么?
期待一两次推动,这会让我的理解更加清晰。
TIA。
在第一个片段中,锁保护是一个临时变量,并在语句末尾删除,而在第二个和第三个片段中,它是一个普通变量,并在作用域末尾删除。
当您这样做时let v = a_mutex.lock().unwrap();,您将 分配MutexGuard给一个变量。与所有变量一样,它被删除在作用域的末尾,即try_lock().
但是,当您调用to_string()它时,锁不会存储在任何地方 - 只有字符串存储在变量中。因此,锁是暂时的。有时,当出现在let语句中时,临时变量会扩展至作用域末尾,但当这是方法调用 ( temporary.method()) 时,它们不会扩展,并且会在调用之前在语句末尾处被删除try_lock()。