如何为RustBox实现Sync?

时间:2017-10-20 14:26:22

标签: multithreading rust thread-safety

我是Rust的新手。我正在努力从线程中的RustBox type包中传递rustbox

我想按下 q 键并让它在(1,1)处显示+符号2秒,而我按 w 键那些2秒在(1,2)处显示另一个+符号。

我为同一个逻辑编写了一些代码:

extern crate rustbox;

use std::thread;
use std::time::Duration;

use rustbox::{Color, RustBox};
use rustbox::Key;


fn mark_at(x: usize, y: usize, rustbox: &RustBox) {
    rustbox.print(x, y, rustbox::RB_BOLD, Color::Black, Color::White, "+");
    thread::spawn(move || {
        let delay = Duration::from_millis(2000);
        thread::sleep(delay);
        rustbox.print(x, y, rustbox::RB_BOLD, Color::Black, Color::White, " ");
    });
}


fn main() {
    let rustbox = match RustBox::init(Default::default()) {
        Result::Ok(v) => v,
        Result::Err(e) => panic!("{}", e),
    };
    rustbox.print(1, 1, rustbox::RB_BOLD, Color::Black, Color::White, " ");
    rustbox.print(1, 2, rustbox::RB_BOLD, Color::Black, Color::White, " ");

    loop {
        rustbox.present();
        match rustbox.poll_event(false) {
            Ok(rustbox::Event::KeyEvent(key)) => {
                match key {
                    Key::Char('q') => {
                        mark_at(1, 1, &rustbox);
                    }
                    Key::Char('w') => {
                        mark_at(1, 2, &rustbox);
                    }
                    Key::Esc => { break; }
                    _ => { }
                }
            },
            Err(e) => panic!("{}", e),
            _ => { }
        }
    }
}

它给了我:

error[E0277]: the trait bound `*mut (): std::marker::Sync` is not satisfied in `rustbox::RustBox`
  --> src/main.rs:12:5
   |
12 |     thread::spawn(move || {
   |     ^^^^^^^^^^^^^ `*mut ()` cannot be shared between threads safely
   |
   = help: within `rustbox::RustBox`, the trait `std::marker::Sync` is not implemented for `*mut ()`
   = note: required because it appears within the type `std::marker::PhantomData<*mut ()>`
   = note: required because it appears within the type `rustbox::RustBox`
   = note: required because of the requirements on the impl of `std::marker::Send` for `&rustbox::RustBox`
   = note: required because it appears within the type `[closure@src/main.rs:12:19: 16:6 rustbox:&rustbox::RustBox, x:usize, y:usize]`
   = note: required by `std::thread::spawn`

error: aborting due to previous error

如何为Sync类型实施RustBox,以便上述代码可以使用?

1 个答案:

答案 0 :(得分:1)

RustBox没有实现Send,所以没有(安全的)方法在线程之间共享它(似乎你已经找到了尚未合并的拉取请求https://github.com/gchp/rustbox/pull/65支持Send)。

如果拉取请求合并,您可以将RustBox包裹在Mutex中,即Mutex<RustBox>,并且可以在线程之间共享对它的引用。

但是你会遇到生命周期问题:你的rustbox引用的活动时间不足以使用它生成一个新线程,因此你必须将它包装在Arc中。

use std::sync::{Arc,Mutex};

fn mark_at(x: usize, y: usize, rustbox: &Arc<Mutex<RustBox>>) {
    rustbox.lock().unwrap().print(x, y, rustbox::RB_BOLD, Color::Black, Color::White, "+");
    let rustbox = rustbox.clone(); // increment reference counter
    thread::spawn(move || {
        let delay = Duration::from_millis(2000);
        thread::sleep(delay);
        rustbox.lock().unwrap().print(x, y, rustbox::RB_BOLD, Color::Black, Color::White, " ");
    });
}

main函数中,您必须包装rustbox

let rustbox = Arc::new(Mutex::new(rustbox));
每次使用时都会

lock()

确保不要将锁定时间过长;它可能有助于使用辅助变量使其更明确,例如:

let pe = rustbox.lock().unwrap().poll_event(false);
match pe {
// ...
}