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%)并非如此。重要的是要牢记这一点,而不是把重点放在错误的问题上
这个问题与全局共享状态有关。尽量避免这样。(是的,我知道这并不总是可能的)。非常感谢!这解决了我在这个版本和它所基于的复杂真实版本上的问题。你有没有可能愿意描述一下你用来解决这个问题的过程?如果没有你的简化例子,我是不会解决这个问题的!好的,我明天会补充一些关于这个过程的细节。