Rust 在单个表达式中对同一变量的第二个锁无限期地阻塞
我有一个Rust 在单个表达式中对同一变量的第二个锁无限期地阻塞,rust,deadlock,Rust,Deadlock,我有一个节点包含一个共享协议上的互斥体,该互斥体反过来在线程池中的不同线程之间使用: use std::sync::{Arc, Mutex}; pub struct Node { thread_pool: ThreadPool, protocol: Arc<Mutex<Protocol>>, } pub struct Protocol {} impl Protocol { pub fn is_leader(&self) -> bo
节点
包含一个共享协议
上的互斥体
,该互斥体反过来在线程池中的不同线程之间使用:
use std::sync::{Arc, Mutex};
pub struct Node {
thread_pool: ThreadPool,
protocol: Arc<Mutex<Protocol>>,
}
pub struct Protocol {}
impl Protocol {
pub fn is_leader(&self) -> bool {
// Do stuff...
}
pub fn is_co_leader(&self) -> bool {
// Do stuff...
}
}
但是,如果将方法调用的值分配给两个变量,则一切都会按预期进行:
impl Node {
pub fn sign(&mut self) {
let protocol_handler = Arc::clone(&self.protocol);
self.thread_pool.execute(move || {
let is_leader = protocol_handler.lock().unwrap().is_leader();
let is_co_leader = protocol_handler.lock().unwrap().is_co_leader();
if !is_leader && !is_co_leader {
// Either this will be executed
}
// or this ...
})
}
}
在第一种情况下,是否存在导致锈菌行为无限期等待的具体原因?以下是针对您的问题的MCVE:
use std::sync::Mutex;
fn main() {
let foo = Mutex::new(42i32);
let f1 = (*foo.lock().unwrap()).count_ones();
println!("f1: {}", f1);
let f2 = (*foo.lock().unwrap()).count_zeros();
println!("f2: {}", f2);
let tot = (*foo.lock().unwrap()).count_ones() + (*foo.lock().unwrap()).count_zeros();
println!("tot: {}", tot);
}
运行此代码时,它将打印f1
和f2
,然后在尝试计算tot
时挂起
问题是Mutex::lock
返回一个MutexGuard
,当锁超出范围时,它会自动释放锁。在上面的示例中,防护在使用它们的表达式末尾超出范围。所以当我写的时候:
let f1 = (*foo.lock().unwrap()).count_ones();
let tot = (*foo.lock().unwrap()).count_ones() + (*foo.lock().unwrap()).count_zeros();
我获取锁,读取值,然后释放锁。因此,在计算f2时锁是自由的
然而,当我写作时:
let f1 = (*foo.lock().unwrap()).count_ones();
let tot = (*foo.lock().unwrap()).count_ones() + (*foo.lock().unwrap()).count_zeros();
我获取锁,读取值,再次尝试获取锁,并且只释放线末端的两个防护装置。当我第二次尝试获取锁而没有首先释放锁时,这会导致代码死锁
请注意,正如trentcl所评论的,如果互斥锁在两次锁定之间发生变化,那么两步示例将受到竞争条件的影响。您更应该使用以下内容:
impl Node {
pub fn sign(&mut self) {
let protocol_handler = Arc::clone(&self.protocol);
self.thread_pool.execute(move || {
let handler = protocol_handler.lock().unwrap();
if !handler.is_leader && !handler.is_co_leader {
// Either this will be executed
}
// or this ...
})
}
}
对我来说,你的两个变种没有区别。请提供一个。欢迎使用堆栈溢出!请检查如何创建一个,然后检查您的问题以将其包括在内。我们无法说出代码中存在哪些板条箱、类型、特征、字段等。例如,
ThreadPool
来自哪里?构建节点并调用它的代码在哪里?为什么返回bool
的函数不返回任何值?试着制造一些能再现你在网络上的错误的东西,或者你可以在一个全新的货运项目中再现它。也有。这看起来真的很有趣。如果另一个线程在是\u leader()
和是\u co\u leader()
之间发生变异,该怎么办?我怀疑您应该只lock()
一次(可能在if
语句之后才释放锁)。