两个线程是否可以同时锁定一个互斥体(使用互斥体包装器)



这个问题来自std::condition_variable 的一个例子

据我所知,当我构建一个新的thread时,它会立即开始执行。

所以我想知道,worker_thread()中的cv.wait(lk, []{return ready;});main中的std::lock_guard<std::mutex> lk(m);会同时锁定互斥体吗?这会发生吗?

(从cppreference我知道std::condition_variable::waitstd::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(),然后代码将按预期工作。这很不幸,因为它迟早会锁定,很可能是在您向最重要的客户演示代码时。

相关内容

最新更新