Reputation: 6039
I am struggling with sending a custom struct over channel.
I wrapped the value in an Arc
and Mutex
as described in the tutorial,
but it doesn't compile anyway.
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
I am using Rust 1.10.0 (cfcb716cf 2016-07-03).
Upvotes: 0
Views: 2477
Reputation: 430663
Look at this 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);
});
}
And the error message:
`std::sync::mpsc::Sender` cannot be shared between threads safely; required because of the requirements on the impl of `std::marker::Send` for ` & std::sync::mpsc::Sender`
(emphasis mine)
By default, a closure captures a reference to any variables used within it. This is what you want most of the time, as giving up ownership is more restrictive for the creator of the closure. Using a reference allows the captured value to be shared between outside the closure and inside and doesn't require moving any bits around.
In this case, you do want to give ownership of input_tx
to the closure. This is because ownership of the closure itself will be given to a new thread, so the closure and everything in it needs to be safe to be handed to another thread. A reference to a Sender
may not be shared among threads.
A move
closure requests that ownership of any captured variables be transferred to the closure. By doing this, there is no sharing and all the requirements are met. As aSpex said:
let input_thread = thread::spawn(move || {
input_tx.send(Command::Quit);
});
Occasionally you need to transfer ownership of some captured variables but want to share others. Since move
closures are all-or-nothing, you need to be more explicit in this case. You can simply take a reference before the closure:
let a = 42;
let a_ref = &a;
let input_thread = thread::spawn(move || {
println!("{}", a_ref);
});
This doesn't work because the reference to a
is not 'static
, but shows the general idea.
Upvotes: 2
Reputation: 5216
The closure passed to thread::spawn()
must be move
(FnOnce
). Arc
and Mutex
are not needed:
let input_thread = thread::spawn(move || {
input_tx.send(Command::Quit);
});
Upvotes: 3