无法通过通道发送结构:mpsc :: Sender无法在线程之间安全地共享

时间:2016-07-11 09:16:50

标签: multithreading rust

我正在努力通过频道发送自定义结构。

我按照教程中的说明将值包装在ArcMutex中, 但它无论如何都不会编译。

extern crate num;

use num::bigint::BigInt;
use std::io::{self, Write};
use std::sync::mpsc;
use std::thread;
use readline::readline as ask;
use std::sync::{Arc, Mutex};

enum Command {
    Quit,
    Help,
    Factorial { n: BigInt },
    Error { msg: String },
}

fn main() {
    let (input_tx, input_rx) = mpsc::channel();
    let input_thread = thread::spawn(|| {
        input_tx.send(Arc::new(Mutex::new(Command::Quit)));
    });
}
error: the trait bound `std::sync::mpsc::Sender<std::sync::Arc<std::sync::Mutex<Command>>>: std::marker::Sync` is not satisfied [E0277]
    let input_thread = thread::spawn(|| {
                       ^~~~~~~~~~~~~
help: run `rustc --explain E0277` to see a detailed explanation
note: `std::sync::mpsc::Sender<std::sync::Arc<std::sync::Mutex<Command>>>` cannot be shared between threads safely
note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<std::sync::Arc<std::sync::Mutex<Command>>>`
note: required because it appears within the type `[closure@src/main.rs:25:38: 65:6 input_tx:&std::sync::mpsc::Sender<std::sync::Arc<std::sync::Mutex<Command>>>]`
note: required by `std::thread::spawn`
error: aborting due to previous error

我正在使用Rust 1.10.0(cfcb716cf 2016-07-03)。

2 个答案:

答案 0 :(得分:2)

传递给thread::spawn()的关闭必须是moveFnOnce)。 Arc不需要:

Mutex

答案 1 :(得分:1)

看看这个MCVE

use std::thread;
use std::sync::mpsc;

enum Command {
    Quit,
    Error { msg: String },
}

fn main() {
    let (input_tx, input_rx) = mpsc::channel();
    let input_thread = thread::spawn(|| {
        input_tx.send(Command::Quit);
    });
}

错误信息:

  

`std :: sync :: mpsc :: Sender`不能安全地在线程之间共享;因为`&amp; std :: sync :: mpsc :: Sender`的`std :: marker :: Send`的impl要求而需要

(强调我的)

默认情况下,闭包会将引用捕获到其中使用的任何变量。这是你大多数时候想要的,因为放弃所有权对于关闭的创建者来说更具限制性。使用引用允许捕获的值在闭包之外和内部之间共享,并且不需要移动任何位。

在这种情况下,您执行希望将input_tx的所有权授予关闭。这是因为闭包本身的所有权将被赋予一个新线程,因此闭包及其中的所有内容都需要安全地传递给另一个线程。 <{1}}的引用可能不会在线程之间共享。

A move closure请求将所有捕获变量的所有权转移到闭包。通过这样做,没有共享并且满足所有要求。正如aSpex said

Sender

有时您需要转移某些捕获变量的所有权,但希望与其他人共享。由于let input_thread = thread::spawn(move || { input_tx.send(Command::Quit); }); 闭包是全有或全无,在这种情况下你需要更明确。您可以在关闭之前简单地参考:

move

这不起作用,因为对let a = 42; let a_ref = &a; let input_thread = thread::spawn(move || { println!("{}", a_ref); }); 的引用不是a,而是显示了一般的想法。