Moving Arc Mutex Ncurses window down thread still doesn't implement send

307 views Asked by At

I'm building an ncurses interface for a little thing I'm working on. For the input, I want to read it non blocking. I figured I could wrap the WINDOW in an Arc Mutex but this doesn't seem to work, as it still complains about send. Is this because the implementation of ncurses is unsafe? How can I solve this? Ideally, I'd have this work with a callback instead of the tx, so I can cut the dependency from the view up the stack, but I couldn't get that closure to Send either.

I'm using this library: https://github.com/jeaye/ncurses-rs

Simplified code:

pub struct View {
    max_x: i32,
    max_y: i32,
    messages_window: WINDOW,
    input_window: Arc<Mutex<WINDOW>>
}

pub fn init(&mut self, input_tx: mpsc::Sender<DispatchMessage>) {
        let input_window = self.input_window.clone();
        thread::spawn(move || {
            loop {
                let input_window = input_window.lock().unwrap();
                draw_prompt(input_window);
                let input = prompt_input(input_window);
                input_tx.send(input_to_message(input)).unwrap();
            }
        });
}

fn prompt_input(input: WINDOW) -> String {
    let mut string = String::new();
    wgetstr(input, &mut string);
    string
}

fn draw_prompt(input: WINDOW) {
    wclear(input);
    let top = 0 as chtype;
    let bottom = ' ' as chtype;
    let empty = ' ' as chtype;
    wborder(input, empty,empty,top,bottom,empty,empty,empty,empty);
    mvwprintw(input, 1, 1, ">> ");
    wrefresh(input);
}

And the errors I get:

src/view.rs:40:33: 40:45 error: mismatched types:
 expected `*mut ncurses::ll::WINDOW_impl`,
    found `std::sync::mutex::MutexGuard<'_, *mut ncurses::ll::WINDOW_impl>`
(expected *-ptr,
    found struct `std::sync::mutex::MutexGuard`) [E0308]
src/view.rs:40                     draw_prompt(input_window);
                                               ^~~~~~~~~~~~
note: in expansion of closure expansion
src/view.rs:37:27: 44:14 note: expansion site
src/view.rs:40:33: 40:45 help: run `rustc --explain E0308` to see a detailed explanation
src/view.rs:41:46: 41:58 error: mismatched types:
 expected `*mut ncurses::ll::WINDOW_impl`,
    found `std::sync::mutex::MutexGuard<'_, *mut ncurses::ll::WINDOW_impl>`
(expected *-ptr,
    found struct `std::sync::mutex::MutexGuard`) [E0308]
src/view.rs:41                     let input = prompt_input(input_window);
                                                            ^~~~~~~~~~~~
note: in expansion of closure expansion
src/view.rs:37:27: 44:14 note: expansion site
src/view.rs:41:46: 41:58 help: run `rustc --explain E0308` to see a detailed explanation
src/view.rs:37:13: 37:26 error: the trait `core::marker::Send` is not implemented for the type `*mut ncurses::ll::WINDOW_impl` [E0277]
src/view.rs:37             thread::spawn(move || {
                           ^~~~~~~~~~~~~
src/view.rs:37:13: 37:26 note: `*mut ncurses::ll::WINDOW_impl` cannot be sent between threads safely
src/view.rs:37             thread::spawn(move || {
                           ^~~~~~~~~~~~~
error: aborting due to 3 previous errors

Manually dereferencing the window removes the type errors, but I figured I'd leave it in as it might be an indication of what's wrong.

1

There are 1 answers

1
Chris Morgan On BEST ANSWER

Arc<T> implements Send where T implements both Send and Sync. Mutex<T> implements Send and Sync where T implements Send. So Arc<Mutex<T>> only implements Send if T implements Send. Remember that Send means “Types able to be transferred across thread boundaries.” Arc<Mutex<T>> allows access to its contents from multiple threads, purely taking care of ownership and mutability issues, so if the underlying type cannot be transferred across thread boundaries it won’t help. You may well need to do all your ncurses operations from one thread.

Raw pointers explicitly do not implement Send because there can be no guarantees about it. You can construct types on top of it which explicitly implement Send, thus providing a guarantee that the contained raw pointer is in fact safe for transferring across thread boundaries.