C++ std::condition_变量在std::condition_变量::notify_all()从其他线程后未正确唤醒

C++ std::condition_变量在std::condition_变量::notify_all()从其他线程后未正确唤醒,c++,condition-variable,wakeup,C++,Condition Variable,Wakeup,此代码是实际项目代码的简化。主线程创建工作线程并使用std::condition\u变量等待工作线程真正启动。在std::condition_变量在当前线程状态变为“ThreadState::Stopping”后唤醒的代码中-这是工作线程发出的第二个通知,即当当前线程状态变为“ThreadState::Starting”时,主线程在第一个通知后未唤醒。结果是僵局。为什么会发生这种情况?为什么std::condition_变量在第一个线程事件后未唤醒。notify_all() intmain()

此代码是实际项目代码的简化。主线程创建工作线程并使用std::condition\u变量等待工作线程真正启动。在std::condition_变量在当前线程状态变为“ThreadState::Stopping”后唤醒的代码中-这是工作线程发出的第二个通知,即当当前线程状态变为“ThreadState::Starting”时,主线程在第一个通知后未唤醒。结果是僵局。为什么会发生这种情况?为什么std::condition_变量在第一个线程事件后未唤醒。notify_all()

intmain()
{
std::thread\u var;
结构线程状态{
枚举类型{已停止,已启动,正在停止};
};
ThreadState::Type current\u thread\u state=ThreadState::Stopped;
std::互斥线程\u互斥;
std::条件变量线程事件;
while(true){
{
std::唯一锁lck(线程互斥);
线程var=std::move(std::thread([&](){
{
std::唯一锁lck(线程互斥);

cout一旦调用
notify_all
方法,您的主线程和工作线程(完成工作后)这两个线程都试图在
thread\u互斥体上获得锁。如果您的工作负载很小,如您的示例中所示,工作线程很可能在主线程之前获得锁,并在主线程读取它之前将状态设置回
ThreadState::Stopped
。这会导致死锁

尝试添加一个重要的工作负载,例如

std::this_thread::sleep_for( std::chrono::seconds( 1 ) );

对于工作线程。死锁的可能性现在要小得多。当然,这并不是解决问题的方法。这只是为了说明问题。

一旦调用
notify_all
方法,主线程和工作线程(完成工作后)这两个线程都试图在
thread\u互斥体上获得锁。如果您的工作负载很小,如您的示例中所示,工作线程很可能在主线程之前获得锁,并在主线程读取它之前将状态设置回
ThreadState::Stopped
。这会导致死锁

尝试添加一个重要的工作负载,例如

std::this_thread::sleep_for( std::chrono::seconds( 1 ) );

对于工作线程。死锁的可能性现在要小得多。当然,这并不是解决问题的方法。这只是为了说明问题。

一旦调用
notify_all
方法,主线程和工作线程(完成工作后)这两个线程都试图在
thread\u互斥体上获得锁。如果您的工作负载很小,如您的示例中所示,工作线程很可能在主线程之前获得锁,并在主线程读取它之前将状态设置回
ThreadState::Stopped
。这会导致死锁

尝试添加一个重要的工作负载,例如

std::this_thread::sleep_for( std::chrono::seconds( 1 ) );

对于工作线程。死锁的可能性现在要小得多。当然,这并不是解决问题的方法。这只是为了说明问题。

一旦调用
notify_all
方法,主线程和工作线程(完成工作后)这两个线程都试图在
thread\u互斥体上获得锁。如果您的工作负载很小,如您的示例中所示,工作线程很可能在主线程之前获得锁,并在主线程读取它之前将状态设置回
ThreadState::Stopped
。这会导致死锁

尝试添加一个重要的工作负载,例如

std::this_thread::sleep_for( std::chrono::seconds( 1 ) );

对于工作线程。死锁的可能性现在要小得多。当然,这不是解决问题的方法。这只是为了说明问题。

您有两个线程在运行:一个线程写入
当前线程状态的值两次,另一个线程读取
当前线程状态的值一次


不确定事件序列是写-读还是写-读-写,这两个都是应用程序的有效执行。

有两个线程在运行:一个线程将
当前线程状态的值写入两次,另一个线程将
当前线程状态的值读取一次


不确定事件序列是写-读还是写-读-写,这两个都是应用程序的有效执行。

有两个线程在运行:一个线程将
当前线程状态的值写入两次,另一个线程将
当前线程状态的值读取一次


不确定事件序列是写-读还是写-读-写,这两个都是应用程序的有效执行。

有两个线程在运行:一个线程将
当前线程状态的值写入两次,另一个线程将
当前线程状态的值读取一次


不确定事件的顺序是写-写-读还是写-读-写,两者都是应用程序的有效执行。

是的。你说得对。如果在工作线程func中使用comment cout.setstate(std::ios::failbit),则一切正常。但我不完全理解,为什么线程\u event.wait(lck)在第一次之后没有唤醒“TyRexEngult.NoTIFYYAL()”,因为C++文档说明:等待操作原子释放互斥体并暂停线程的执行。当条件变量被通知时,线程被唤醒,互斥体被重新获取。因此,在这种情况下最简单的解决方案是改变<代码>。(当前线程状态!=ThreadState::Started)
而(当前线程状态==ThreadState::Stopped)
@stefaanv,我们必须找到状态ThreadState::Started,保证知道工作线程正在运行。第一次和第二次调用线程事件之间的工作线程中的代码。notify\u all()可以执行任意时间或等待某个事件。@soler:好的,我是针对发布的问题提出了一个解决方案,而不是您的要求。无论如何,问题是您不能保证能够检查确切的状态,所以