移动含Arc的self到新线程时为何出现“Sync未满足”错误?
Hey there! Let's break down why you're hitting this error and how to fix it.
First, the root cause: std::sync::mpsc::Receiver<f32> doesn't implement the Sync trait. Here's why that matters: when you wrap something in Arc<T>, Rust requires that T is both Send (can be moved to another thread) and Sync (can be safely shared across threads). The mpsc Receiver is Send (you can move it to a single thread), but it's not Sync because it's designed to be used by exactly one thread at a time—sharing it across threads would lead to race conditions and undefined behavior.
When you try to pass your Arc<Receiver<f32>> into thread::spawn, the compiler checks that the closure is Send (since it has to move to the new thread). But since Arc<Receiver<f32>> isn't Send (because Receiver isn't Sync), you get that E0277 error.
Now let's look at two solutions depending on your use case:
Solution 1: Ditch Arc (for single-threaded receiving)
If you only need one thread to handle receiving messages, you don't need Arc at all. The Receiver itself is Send, so you can just move it directly into the thread:
use std::sync::mpsc; use std::thread; struct MyStruct { receiver: mpsc::Receiver<f32>, } impl MyStruct { fn start_thread(self) { thread::spawn(move || { // Keep receiving until the sender is dropped while let Ok(value) = self.receiver.recv() { println!("Got value: {}", value); } println!("Receiver closed, exiting thread"); }); } } fn main() { let (sender, receiver) = mpsc::channel(); let my_struct = MyStruct { receiver }; // Start the thread my_struct.start_thread(); // Send some test values sender.send(3.14).unwrap(); sender.send(2.71).unwrap(); // Drop the sender to close the channel drop(sender); // Wait a bit for the thread to finish (in real code, use a JoinHandle) thread::sleep(std::time::Duration::from_secs(1)); }
This works because we're transferring full ownership of the Receiver to the new thread—no sharing, so no need for Arc or Sync.
Solution 2: Use a thread-safe multi-consumer channel (for multi-threaded receiving)
If you need multiple threads to receive messages, the standard mpsc channel won't cut it (since it's single-consumer). Instead, use a channel that supports safe sharing across threads, like the ones from crossbeam-channel:
First, add the dependency to your Cargo.toml:
[dependencies] crossbeam-channel = "0.5"
Then adjust your code:
use crossbeam_channel as channel; use std::sync::Arc; use std::thread; struct MyStruct { receiver: Arc<channel::Receiver<f32>>, } impl MyStruct { fn start_thread(self) { // Clone the Arc for the first thread let receiver_clone = self.receiver.clone(); thread::spawn(move || { while let Ok(value) = receiver_clone.recv() { println!("Thread 1 got: {}", value); } }); // Use the original Arc for a second thread thread::spawn(move || { while let Ok(value) = self.receiver.recv() { println!("Thread 2 got: {}", value); } }); } } fn main() { let (sender, receiver) = channel::unbounded(); let my_struct = MyStruct { receiver: Arc::new(receiver) }; my_struct.start_thread(); sender.send(1.0).unwrap(); sender.send(2.0).unwrap(); drop(sender); thread::sleep(std::time::Duration::from_secs(1)); }
The crossbeam-channel::Receiver implements both Send and Sync, so wrapping it in Arc is safe. This lets multiple threads receive messages (note that each message goes to only one thread, like a queue—if you need broadcast, use channel::broadcast instead).
To recap:
- Use plain
ReceiverwithoutArcif you only need one receiving thread - Use a multi-consumer channel like
crossbeam-channelif you need multiple threads to receive
内容的提问来源于stack exchange,提问作者André T.

