如果我对"while"块发表评论,为什么程序会死机?其中的"yield"线有何影响?

Why the program get deadlocked if I comment the "while" block? How does the "yield" line in it effect?

本文关键字:yield 何影响 影响 while 评论 如果 程序 为什么 死机      更新时间:2023-10-16

我正在学习condition_variable并运行一些示例。我很好奇,如果我对块进行注释,为什么以下代码会死锁。这是一个使用 condition_variable 的简单使用者和生产者示例。我认为这是一个僵局问题,不是吗?

#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
using namespace std;
mutex mtx;
condition_variable cv;
int cargo = 0;
bool shipment_available()
{
return cargo != 0;
}
void consume(int cnt)
{
for (int i = 0; i < cnt; i++)
{
unique_lock<mutex> lck(mtx);
cv.wait(lck, shipment_available);
printf("%dn", cargo);
cargo = 0;
}
}
int main()
{
thread consumer_thread(consume, 10);
for (int i = 0; i < 10; i++)
{
//while (shipment_available())    // Dead lock without this block
//{
//    std::this_thread::yield();
//}
unique_lock<mutex> lck(mtx);
cargo = i + 1;
cv.notify_one();
}
consumer_thread.join();
}

如果我取消注释该块,它运行良好。

因此,请了解这种极有可能的可能性:

  1. main()启动使用者线程。
  2. 在线程获取互斥锁之前,main()锁定它,递增cargo,并触发通知,然后通过作用域轮换十释放互斥锁。
  3. main()现在向下运行以join使用者线程。
  4. 消费者最终获得互斥锁,并准备等待给定谓词的条件变量(非零货物(。
  5. 谓词已为 true,因此不执行等待。
  6. 消费者将货物归零,然后通过范围旋转释放互斥锁。
  7. 消费者第二次循环,锁定互斥锁,然后检查谓词,只是现在谓词是的,因为cargo确实为零,所以它等待条件变量(释放过程中的互斥锁(一个永远不会出现的信号。唯一发送过该信号的是main(),它只是在等待消费者线程加入,现在这种情况永远不会发生。

简而言之,您似乎相信条件变量信号会叠加。事实并非如此。如果在发布通知时没有人主动等待通知,它就会丢失到以太币中。

最后,这很重要,您的"修复"本身是完全错误的。shipment_available函数检查谓词数据(即必须由覆盖它的互斥锁保护的数据,不仅用于修改,而且用于检查(。检查互斥锁是否未锁定main是争用条件的秘诀。

我的建议是将货物减少一个,而不是将其归零。或者,您可以在将i值归零之前将cargo的值递增,从而加速i的上升到cnt限制,但您似乎使用的是递增的货物量,因此您必须相应地进行其他调整。