05 July 2023

C++ 核心指南目录

“Don’t wait without a condition”

理由

在 wait 中不设置判断条件的话,会发现线程醒来之后并没有任务要处理。

坏例子

std::condition_variable cv;
std::mutex mx;

void thread1()
{
    while (true) {
        // do some work ...
        std::unique_lock<std::mutex> lock(mx);
        cv.notify_one();    // wake other thread
    }
}

void thread2()
{
    while (true) {
        std::unique_lock<std::mutex> lock(mx);
        cv.wait(lock);    // might block forever
        // do work ...
    }
}

这里,如果某个其他线程用掉了 thread1 的通知, thread2 会一直等待。

例子

template<typename T>
class Sync_queue {
public:
    void put(const T& val);
    void put(T&& val);
    void get(T& val);
private:
    mutex mtx;
    condition_variable cond;    // this controls access
    list<T> q;
};

template<typename T>
void Sync_queue<T>::put(const T& val)
{
    lock_guard<mutex> lck(mtx);
    q.push_back(val);
    cond.notify_one();
}

template<typename T>
void Sync_queue<T>::get(T& val)
{
    unique_lock<mutex> lck(mtx);
    cond.wait(lck, [this] { return !q.empty(); });    // prevent spurious wakeup
    val = q.front();
    q.pop_front();
}

现在,如果消息是空的,调用 get() 的线程会醒来,发现其他线程在它之前已经调用了 geet() ,那么这个线程会马上睡眠,继续等待。

强化

标记 wait 中没设置判断条件的情况。