Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/rust/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/assembly/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Rust 在单个表达式中对同一变量的第二个锁无限期地阻塞_Rust_Deadlock - Fatal编程技术网

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
语句之后才释放锁)。