use*_*793 8 c++ multithreading atomic condition-variable c++17
我有以下代码,注释行上的死锁.基本上f1和f2作为程序中的单个线程运行.f1期望i为1并递减它,通知cv.f2期望i为0并递增它,通知cv.我假设如果f2将i增加到1,则调用死锁,调用cv.notify(),然后f1读取过时的i值(为0),因为互斥锁和i之间没有内存同步,然后等待并且永远不会被唤醒起来.然后f2也进入睡眠状态,现在两个线程都在等待一个永远不会被通知的cv.
如何编写此代码以便不会发生死锁?基本上我想要实现的是拥有一些由两个线程更新的原子状态.如果其中一个线程的状态不正确,我不想旋转; 相反,我想使用cv功能(或类似的东西)在值正确时唤醒线程.
我使用g ++ - 7用O3编译代码(尽管在O0和O3中都发生了死锁).
#include <atomic>
#include <condition_variable>
#include <iostream>
#include <mutex>
#include <thread>
std::atomic_size_t i{0};
std::mutex mut;
std::condition_variable cv;
void f1() {
while (1) {
{
std::unique_lock<std::mutex> lk(mut);
cv.wait(lk, []() { return i.load() > 0; }); // deadlocks
}
--i;
cv.notify_one();
std::cout << "i = " << i << std::endl; // Only to avoid optimization
}
}
void f2() {
while (1) {
{
std::unique_lock<std::mutex> lk(mut);
cv.wait(lk, []() { return i.load() < 1; }); // deadlocks
}
++i;
cv.notify_one();
std::cout << "i = " << i << std::endl; // Only to avoid optimization
}
}
int main() {
std::thread t1(f1);
std::thread t2(f2);
t1.join();
t2.join();
return 0;
}
Run Code Online (Sandbox Code Playgroud)
编辑:cout只是为了避免编译器优化.
我认为问题是i可以改变的值,可以notify_one在另一个线程评估后的间隔中调用,return i.load() > 0;但在lambda调用返回之前,cv恢复等待.这样,另一个线程将不会观察到原子变量的变化,也没有人将其唤醒以再次检查.这可以通过在更改变量时锁定互斥量来解决,但这样做会破坏原子的目的.