有时候 thread需要等待某种外部事件,比如另一个 thread完成了任务或是已经过去了段时间。最简单的“事件”就是时间流逝。请考虑如下的代码

    1. //获取时间差
    2. using namespace std:chrono; //见35.2节
    3. auto t0 = high_resolution_clock::now();
    4. this_thread::sleep_for(milliseconds{20});
    5. auto t1= high_resolution_clock:now();
    6. cout << duration_cast<nanoseconds>(t1-t0).count()<<"nanoseconds passed\n";

    注意,我甚至没有启动一个 thread, this thread默认指向唯一的线程(见42.2.6节)。
    我使用 duration_cast将时钟单位调整为期望的纳秒。要想尝试更多关于时间的操作请先阅读5.41节和35.2节。C++的时间功能位于<chrono>头文件中。
    通过外部事件实现线程间通信的基本方法是使用 condition_variable,它定义在<condition_variable>中(见42.3.4节)。 condition_variable提供了一种机制,允许一个thread等待另一个 thread。特别是,它允许一个thread等待某个条件( condition,通常称为一个事件, event)发生,这种条件通常是其他 thread完成工作产生的结果。
    考虑两个 thread通过 queue传递消息的经典例子。为简单起见,我声明 queue对象,以及生产者、消费者共享 queue同时避免竞争条件的机制如下:

    1. class Message{ //通信的对象
    2. //...
    3. }
    4. queue<Message> mqueue; //消息的队列
    5. condition_variable mcond; //通信用的条件变量
    6. mutex mmutex; //锁机制

    其中的类型queue,condition_variablemutex由标准库提供。
    consumer()读取并处理Message:

    1. void consumer()
    2. {
    3. while(true)
    4. {
    5. unique_lock<mutex> lck{mmutex}; //获取mmutex
    6. while(mcord.wait(lck))
    7. {
    8. //do nothing //释放lck并等待
    9. } //被唤醒后重新获取lck
    10. auto m=mqueue.front(); //获取消息
    11. mqueue.pop();
    12. lck.unlock();
    13. //处理m
    14. }
    15. }

    此例中,我通过一个 mutex上的 unique_lock显式保护对 queuecondition_variable的操作。线程在 condition_variable上等待时,会释放已持有的锁,直至被唤醒后(此时队列非空)重新获取锁。
    对应的 producer可以这样编写:

    1. void producer()
    2. {
    3. while(true)
    4. {
    5. Message m;
    6. //填入消息
    7. unique_lock<mutex> lck{mmutex}; //保护队列上的操作
    8. mqueue.push(m);
    9. mcond.notify_one(); //通知
    10. } //释放锁(在作用域结束)
    11. }

    使用 condition_variable可以帮助我们完成很多既优雅又有效的数据共享,但是绝非一直如此(见42.3.4节)。