我正在使用discord crate,它使用事件循环。我需要同时检查事件,而我正在接受用户输入:
let clone = context.clone();
thread::spawn(
move || loop {
match clone.lock().unwrap().gateway.recv_event() {
Ok(event) => {
// println!("Updating state: {:?}", event);
clone.lock().unwrap().state.update(&event)
},
Err(err) => {
stderr!("Error receiving: {}", err);
},
}
}
);
这不起作用,因为它保持锁定......那么
呢println!("Locking");
let mut gateway = {
&mut clone.lock().unwrap().gateway
};
println!("Unlocked? {:?}", clone);
match gateway.recv_event() {
Ok(event) => {
这似乎也不起作用:
Locking
Unlocked? Mutex { <locked> }
如何解决这个问题?
如果有一种方法可以在不锁定的情况下访问互斥锁的内容,那么我可能会感觉最好。
答案 0 :(得分:1)
我建议你再次阅读Mutex
以及锁定守卫是什么(另请参阅Borrow data out of a mutex "borrowed value does not live long enough",其中存在类似问题)。问题是clone.lock().unwrap().gateway.recv_event()
创建了一个Mutex锁定保护,保留到完整的match
语句。例如,让我们重新定义Something
:
#[derive(Debug)]
struct Something(i32);
impl Something {
pub fn get_some_event(&self) -> i32 {
thread::sleep(Duration::from_secs(1));
self.0
}
}
此代码有效:
let variable = Mutex::new(Something(4));
match variable.lock().unwrap().get_some_event()
{
5 => {
variable.lock().unwrap();
}
_ => {
println!("{:?}", variable); // Still locked
}
}
println!("{:?}", variable); // no longer locked!
但这会导致死锁(因为Rust中的标准互斥锁不可重入):
let variable = Mutex::new(Something(5));
match variable.lock().unwrap().get_some_event()
{
5 => {
variable.lock().unwrap(); // deadlock!
}
_ => {
println!("{:?}", variable);
}
}
println!("{:?}", variable);
解决方案在于,您在获取事件时(或执行其他操作时)只需要锁定。如果不这样做,请确保丢弃相应的锁。
let r = clone.lock().unwrap().gateway.recv_event(); // get result + drop lock
match event {
Ok(event) => {
clone.lock().unwrap().state.update(&event) // also ok
},
...
}