【问题标题】:Cannot send a struct over channel: mpsc::Sender cannot be shared between threads safely无法通过通道发送结构:mpsc::Sender 无法在线程之间安全共享
【发布时间】:2016-07-11 09:16:50
【问题描述】:

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

如教程中所述,我将值包装在 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)。

【问题讨论】:

标签: multithreading rust


【解决方案1】:

传递给thread::spawn() 的闭包必须是move (FnOnce)。不需要ArcMutex

let input_thread = thread::spawn(move || {
    input_tx.send(Command::Quit);
});

【讨论】:

    【解决方案2】:

    看看这个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` 不能在线程之间安全地共享;需要,因为对 `& std::sync::mpsc::Sender` 的 `std::marker::Send` 的 impl 有要求

    (强调我的)

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

    在这种情况下,您确实希望将 input_tx 的所有权授予闭包。这是因为闭包本身的所有权将被赋予一个新线程,因此闭包和其中的所有内容都需要安全地交给另一个线程。对Sender引用可能不会在线程之间共享。

    move closure 请求将任何捕获变量的所有权转移给闭包。通过这样做,没有共享并且满足所有要求。作为aSpex said

    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 的引用不是'static,而是显示了大致思路。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-07-09
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-01-01
      • 1970-01-01
      • 2021-07-06
      • 1970-01-01
      相关资源
      最近更新 更多