如何冻结一个线程并从另一个线程通知它?

How to freeze a thread and notify it from another?

我需要在 Rust 中暂停当前线程并从另一个线程通知它。在 Java 我会写:

synchronized(myThread) {
    myThread.wait();
}

从第二个线程(恢复主线程):

synchronized(myThread){
    myThread.notify();
}

是否可以在 Rust 中做同样的事情?

使用发送类型 () 的通道可能是最简单的:

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

let (tx,rx) = channel();

// Spawn your worker thread, giving it `send` and whatever else it needs
thread::spawn(move|| {
    // Do whatever
    tx.send(()).expect("Could not send signal on channel.");
    // Continue
});

// Do whatever
rx.recv().expect("Could not receive from channel.");
// Continue working

() 类型是因为它实际上是零信息,这意味着很明显您只是将它用作信号。它的大小为零这一事实意味着它在某些情况下也可能更快(但实际上可能不会比正常的机器字写入快)。

如果你只是需要通知程序一个线程完成,你可以抓住它的join guard等待它加入。

let guard = thread::spawn( ... ); // This will automatically join when finished computing

guard.join().expect("Could not join thread");

在 Rust 中有多种方法可以实现这一点。

如果我没记错的话,Java 中的基础模型是每个对象都包含一个互斥体和一个条件变量。所以使用互斥锁和 condition variable 会起作用...

...但是,我个人会改为使用频道:

  • "waiting"线程有通道的接收端,等待
  • "notifying"线程有通道的发送端,发送消息

它比条件变量更容易操作,特别是因为在锁定变量时不存在意外使用不同互斥锁的风险。

std::sync::mpsc has two channels (asynchronous and synchronous) depending on your needs. Here, the asynchronous one matches more closely: std::sync::mpsc::channel.

您可以使用 std::thread::park() and std::thread::Thread::unpark() 来实现。

在您要等待的线程中,

fn worker_thread() {
    std::thread::park();
}

在已经有线程句柄的控制线程中,

fn main_thread(worker_thread: std::thread::Thread) {
    worker_thread.unpark();
}

请注意,停放线程可能会被虚假唤醒,这意味着该线程有时会在没有任何其他线程对其调用 unpark 的情况下唤醒。您应该在代码中为这种情况做好准备,或者使用接受的答案中建议的 std::sync::mpsc::channel 之类的东西。

有一个 monitor crate 通过在一个方便的结构中组合 MutexCondvar 来提供此功能。

(完全公开:我是作者。)

简而言之,可以这样使用:

    let mon = Arc::new(Monitor::new(false));
    {
        let mon = mon.clone();
        let _ = thread::spawn(move || {
            thread::sleep(Duration::from_millis(1000));

            mon.with_lock(|mut done| {     // done is a monitor::MonitorGuard<bool>
                *done = true;
                done.notify_one();
            });
        });
    }

    mon.with_lock(|mut done| {
        while !*done {
            done.wait();
        }
        println!("finished waiting");
    });

这里,mon.with_lock(...) 在语义上等同于 Java 的 synchronized(mon) {...}