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
Concurrency 为什么不是';t互斥解锁?_Concurrency_Rust_Mutex_Pool - Fatal编程技术网

Concurrency 为什么不是';t互斥解锁?

Concurrency 为什么不是';t互斥解锁?,concurrency,rust,mutex,pool,Concurrency,Rust,Mutex,Pool,我正在尝试为大型Obj类型实现一个全局对象池。以下是池的代码: static mut POOL: Option<Mutex<Vec<Obj>>> = None; static INIT: Once = ONCE_INIT; pub struct Obj; fn get_pool<'a>() -> MutexGuard<'a, Vec<Obj>> { unsafe { match POOL {

我正在尝试为大型
Obj
类型实现一个全局对象池。以下是
池的代码:

static mut POOL: Option<Mutex<Vec<Obj>>> = None;
static INIT: Once = ONCE_INIT;

pub struct Obj;
fn get_pool<'a>() -> MutexGuard<'a, Vec<Obj>> {
    unsafe {
        match POOL {
            Some(ref mutex) => mutex.lock().unwrap(),
            None            => {
                INIT.call_once(|| {
                    POOL = Some(Mutex::new(vec![]));
                });
                get_pool()
            }
        }
    }
}
这是导致问题的代码:

impl Drop for Obj {
    fn drop(&mut self) {
        println!("dropping.");
        println!("hangs here...");
        get_pool().push(Obj {});
    }
}

impl Obj {
    pub fn new() -> Obj {
        println!("initializing");
        get_pool().pop().unwrap_or(Obj {})
        // for some reason, the mutex does not get unlocked at this point...
    }
}
我认为这与
get\u pool
返回值中
MutexGuard
的生存期
'a
有关。坦率地说,我可能对这些寿命参数的工作方式有点困惑


下面是一个示例。感谢您的帮助,祝您圣诞快乐。

问题出在这行:

get_pool().pop().unwrap_or(Obj {})
因为调用了
get_pool()
,所以锁定了互斥锁,直到行尾它才会解锁。但是,在调用
unwrap\u或()。如果vec中存在对象,则不会使用此选项。因为它是稍后创建的,所以它将在释放互斥锁之前被删除。当drop试图锁定互斥锁时,会出现死锁

要解决此问题,请将该语句拆分为两行:

let o = get_pool().pop();
o.unwrap_or(Obj {})
作为相关说明,您可以使用以避免不安全代码:

#![feature(drop_types_in_const)]
use std::sync::{Mutex, MutexGuard};

#[macro_use]
extern crate lazy_static;

lazy_static! {
  static ref POOL: Mutex<Vec<Obj>> = Mutex::new(vec![]);
}

pub struct Obj;

fn get_pool<'a>() -> MutexGuard<'a, Vec<Obj>> {
        POOL.lock().unwrap()
}

impl Drop for Obj {
    fn drop(&mut self) {
        println!("dropping.");
        println!("hangs here...");
        get_pool().push(Obj {});
        println!("not here...");
    }
}

impl Obj {
    pub fn new() -> Obj {
        println!("initializing");
        let o = get_pool().pop();
        o.unwrap_or(Obj {})
    }
}

fn main() {
    Obj::new();
    Obj::new();
    println!("Now reaches this point.");
}
#![特征(拖放类型常量)]
使用std::sync::{Mutex,MutexGuard};
#[宏_使用]
外部板条箱(静态);
懒惰的人!{
静态引用池:Mutex=Mutex::new(vec![]);
}
pub-struct-Obj;
fn get_pool{
POOL.lock().unwrap()
}
Obj的impl下降{
fn下降(&mut自我){
println!(“下降”);
println!(“挂在这里…”);
get_pool().push(Obj{});
println!(“不在这里…”);
}
}
impl Obj{
pub fn new()->Obj{
println!(“初始化”);
设o=get_pool().pop();
o、 展开或(对象{})
}
}
fn main(){
Obj::new();
Obj::new();
println!(“现在到了这一点。”);
}
编辑

按照要求,我将解释我是如何诊断的

  • 首先,我验证了是否可以使用您提供的样本重现问题。我可以,代码也很简单明了。这一切都很好,我只需要添加一行
    println!(“不在这里……”)
    以100%确保它挂起在上面的语句中,而不是在块的末尾
  • 在第一次扫描中,我注意到
    Obj::new()必须调用两次才能发生问题。因此,下一个目标是找出两个调用之间的差异。(我对生锈的了解还不足以通过阅读代码来发现这个错误)
  • 因为
    POOL
    在第一次调用中没有初始化,所以我在main(
    unsafe{INIT.call_一次(| |{POOL=Some(Mutex::new(vec![]);})}
    的开头添加了初始化,但这并没有改变任何事情
  • 由于在删除
    Obj
    时会向池中添加一个对象,因此我在main(
    get_pool().push(Obj{});
    的开头添加了一个对象。现在它挂起在第一个
    Obj::new()
  • 我可以通过调用
    get_pool().pop().unwrap_或(Obj{})进一步简化它主菜单中的下一个
  • 现在我可以部分删除或拆分该行,以确定它的确切挂起位置。通过这样做,我看到我能够修复它。然后我意识到在那里创建了一个额外的
    Obj
    。请注意,锈蚀借用范围当前为
  • 回想起来,如果我在
    drop()
    中删除包含
    get\u pool()
    的行,并计算调用
    drop()
    的次数,我早就发现了这一点。我没意识到是被叫了三次而不是两次
  • 一般来说,这个问题的标题是“为什么互斥锁不能解锁”。这可能被解释为编译器错误或标准库中的错误。大多数情况下(>99%)并非如此。重要的是要牢记这一点,而不是把重点放在错误的问题上


    这个问题与全局共享状态有关。尽量避免这样。(是的,我知道这并不总是可能的)。

    非常感谢!这解决了我在这个版本和它所基于的复杂真实版本上的问题。你有没有可能愿意描述一下你用来解决这个问题的过程?如果没有你的简化例子,我是不会解决这个问题的!好的,我明天会补充一些关于这个过程的细节。