通过Mutex访问事件循环

时间:2017-06-01 09:11:49

标签: loops events rust

我正在使用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> }

如何解决这个问题?

如果有一种方法可以在不锁定的情况下访问互斥锁的内容,那么我可能会感觉最好。

Example in Playground

The original question is here on reddit.

1 个答案:

答案 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
     },
     ...
}