将 Receiver 移动到线程会抱怨 Sync,但预期会发送

Moving Receiver to thread complains about Sync, but expected Send

我正在尝试通过 Arc 将接收器引用到线程中,这样我就可以通过调度程序进行集中式发布-订阅。但是,我收到以下错误:

src/dispatcher.rs:58:11: 58:24 error: the trait `core::marker::Sync` is not implemented for the type `core::cell::UnsafeCell<std::sync::mpsc::Flavor<dispatcher::DispatchMessage>>` [E0277]
src/dispatcher.rs:58           thread::spawn(move || {
                               ^~~~~~~~~~~~~
src/dispatcher.rs:58:11: 58:24 note: `core::cell::UnsafeCell<std::sync::mpsc::Flavor<dispatcher::DispatchMessage>>` cannot be shared between threads safely
src/dispatcher.rs:58           thread::spawn(move || {

哇!我以为跨频道只需要SendDispatchMessage的代码是:

#[derive(PartialEq, Debug, Clone)]
enum DispatchType {
    ChangeCurrentChannel,
    OutgoingMessage,
    IncomingMessage
}

#[derive(Clone)]
struct DispatchMessage {
   dispatch_type: DispatchType,
   payload: String
}

String 和肯定 Enum 都是 Send,对吧?为什么抱怨Sync

调度相关部分:

pub fn start(&self) {
   let shared_subscribers = Arc::new(self.subscribers);
   for ref broadcaster in &self.broadcasters {
      let shared_broadcaster = Arc::new(Mutex::new(broadcaster));

      let broadcaster = shared_broadcaster.clone();
      let subscribers = shared_subscribers.clone();
      thread::spawn(move || {
         loop {
            let message = &broadcaster.lock().unwrap().recv().ok().expect("Couldn't receive message in broadcaster");
            match subscribers.get(type_to_str(&message.dispatch_type)) {
              Some(ref subs) => { 
                  for sub in subs.iter() { sub.send(*message).unwrap(); }
              },
              None => ()
            }

         }
      });
   }
}

完整的调度程序代码在这个要点中:https://gist.github.com/timonv/5cdc56bf671cee69d3fa

如果它仍然相关,则针对 5-2-2015 每晚构建。

Arc 需要 Sync,在我看来您正试图将频道放入 Arc。频道不是 SyncSenderReceiver

在不知道您要做什么的情况下,以下几点可能对您有所帮助:

  • 可以克隆 Sender,因此您可能 Arc 一个 T 并在多个线程之间共享它,您可以克隆一个 Sender 并发送它有很多线程,因为它 Send
  • 否则(尤其是对于 Receiver,您无法克隆)您必须将其粘贴在 Arc<Mutex<T>> 中,这使得它成为 Sync.

尽管 Jorge 在一般意义上是正确的,但此特定代码的问题在于创建 Arc Mutex 会获取参数的所有权,因此不能作为引用。当您考虑时,这是有道理的。你怎么能锁上不属于你的东西?或者更具体地说,我们需要锁定该内存位置的任何内容,而不是指向它的指针。

在将广播器添加到结构时更改代码以创建 Arc Mutex 解决了问题。这会将那部分代码更改为:

pub fn register_broadcaster(&mut self, broadcaster: &mut Broadcast) {
   let handle = Arc::new(Mutex::new(broadcaster.broadcast_handle()));
   self.broadcasters.push(handle);
}

然后调度程序的启动方法如下所示:

pub fn start(&self) {
   // Assuming that broadcasters.clone() copies the vector, but increase ref count on els
   for broadcaster in self.broadcasters.clone() {
      let subscribers = self.subscribers.clone();
      thread::spawn(move || {
         loop {
            let message = broadcaster.lock().unwrap().recv().ok().expect("Couldn't receive message in broadcaster or channel hung up");
            match subscribers.get(type_to_str(&message.dispatch_type)) {
              Some(ref subs) => { 
                  for sub in subs.iter() { sub.send(message.clone()).unwrap(); }
              },
              None => ()
            }

         }
      });
   }
}