这个问题来自std::condition_variable 的一个例子
据我所知,当我构建一个新的thread
时,它会立即开始执行。
所以我想知道,worker_thread()
中的cv.wait(lk, []{return ready;});
和main
中的std::lock_guard<std::mutex> lk(m);
会同时锁定互斥体吗?这会发生吗?
(从cppreference我知道std::condition_variable::wait
和std::lock_guard
会在构造过程中锁定互斥对象。(
#include <iostream>
#include <string>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex m;
std::condition_variable cv;
std::string data;
bool ready = false;
bool processed = false;
void worker_thread()
{
// Wait until main() sends data
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return ready;});
// after the wait, we own the lock.
std::cout << "Worker thread is processing datan";
data += " after processing";
// Send data back to main()
processed = true;
std::cout << "Worker thread signals data processing completedn";
// Manual unlocking is done before notifying, to avoid waking up
// the waiting thread only to block again (see notify_one for details)
lk.unlock();
cv.notify_one();
}
int main()
{
std::thread worker(worker_thread);
data = "Example data";
// send data to the worker thread
{
std::lock_guard<std::mutex> lk(m);
ready = true;
std::cout << "main() signals data ready for processingn";
}
cv.notify_one();
// wait for the worker
{
std::unique_lock<std::mutex> lk(m);
cv.wait(lk, []{return processed;});
}
std::cout << "Back in main(), data = " << data << 'n';
worker.join();
}
互斥是为了获得资源上的锁,只有一个线程可以获得该锁。互斥锁是原子锁,两个线程无法获得互斥锁上的锁,如果可以,那么它就违背了互斥锁的目的!
互斥被构建为锁定是一个原子操作:无论有多少线程试图锁定,它一次只能在一个线程上完成
"互斥"是"互斥"的缩写;它的目的是在任何时候只允许一个线程锁定互斥对象。
也就是说,这个例子存在严重的问题。它有潜在的死锁,因为它过于努力地对固有的非顺序操作进行排序。
如果main
通过其锁定代码,将ready
设置为true
,并在新线程锁定互斥并调用wait()
之前调用notify()
,则会出现问题。如果发生这种情况,当新线程位于wait()
中时,main
将继续其对wait()
的调用,并且两者都不会通知另一个;他们都在等另一个做点什么。
如果你运气不好,你在测试代码时不会看到这一点;在主线程调用notify()
之前,新线程可能会启动到wait()
,然后代码将按预期工作。这很不幸,因为它迟早会锁定,很可能是在您向最重要的客户演示代码时。