虚假唤醒
https://zhuanlan.zhihu.com/p/652823880
https://www.cnblogs.com/angdh/p/18267978
https://cloud.tencent.com/developer/article/1557403
应用层引起的虚假唤起
这种虚假唤起是由不合理的代码逻辑引起的,具体看代码
#include <condition_variable>
#include <iostream>
#include <thread>
#include <queue>
#include <string>
using namespace std::chrono_literals;
std::condition_variable cv;
std::mutex mtx;
std::queue<std::string> q;
void Producer()
{
std::this_thread::sleep_for(2000ms);
std::cout << "Ready Send notification." << std::endl;
mtx.lock();
q.push("message");
q.push("message");
mtx.unlock();
cv.notify_all();
std::this_thread::sleep_for(200ms);
mtx.lock();
q.push("message");
mtx.unlock();
cv.notify_all();
}
void Consumer()
{
std::cout << "Wait for notification." << std::endl;
std::unique_lock<std::mutex> lck(mtx);
if(q.empty())
cv.wait(lck);
std::string msg = q.front();
q.pop();
mtx.unlock();
std::cout << "Get: " << msg <<std::endl;
}
int main()
{
std::thread producer(Producer);
std::thread consumer(Consumer);
std::thread consumer2(Consumer);
std::thread consumer3(Consumer);
producer.join();
consumer.join();
consumer2.join();
consumer3.join();
return 0;
}
在这个例子中,有一个生产者线程与3个消费者线程,生产者线程第一次会生产2个message,但是notify_all在唤起所有3个消费者后,会有一个消费者获取不到message(最后获取锁的所有权的那个),这样就导致了那个线程被唤起后却无法获取元素。
Wait for notification.
Wait for notification.
Wait for notification.
Ready Send notification.
Get: message
Get: message
Get:
操作系统引起的虚假唤起
当一个线程在wait情况下被唤起时,唤起他的并不是对应的条件变量信号(如pthread_cond_signal或notify_one/signal_one等方法)直接导致的。换句话说,即使没有对线程进行显式的唤醒操作,线程也可能因为某些原因(如操作系统的内部行为)被唤醒,但此时唤醒的条件并不满足,导致线程执行错误或不必要的操作。
- 操作系统并不保证在调用唤醒函数(如pthread_cond_signal)时只唤醒一个或特定的线程。这可能导致多个线程同时被唤醒,而实际上可能只需要唤醒一个
比方说一些来自于操作系统的中断信号,或者出现了另外一个并不与当前wait线程匹配的信号,也有可能将此wait线程唤起。
解决办法,判断标记值
#include <condition_variable>
#include <iostream>
#include <thread>
#include <queue>
#include <string>
using namespace std::chrono_literals;
std::condition_variable cv;
std::mutex mtx;
std::queue<std::string> q;
void Producer()
{
std::this_thread::sleep_for(2000ms);
std::cout << "Ready Send notification." << std::endl;
mtx.lock();
q.push("message");
q.push("message");
mtx.unlock();
cv.notify_all();
std::this_thread::sleep_for(200ms);
mtx.lock();
q.push("message");
mtx.unlock();
cv.notify_all();
}
void Consumer()
{
std::cout << "Wait for notification." << std::endl;
std::unique_lock<std::mutex> lck(mtx);
if(q.empty())
cv.wait(lck,[]{return !q.empty();});
std::string msg = q.front();
q.pop();
mtx.unlock();
std::cout << "Get: " << msg <<std::endl;
}
int main()
{
std::thread producer(Producer);
std::thread consumer(Consumer);
std::thread consumer2(Consumer);
std::thread consumer3(Consumer);
producer.join();
consumer.join();
consumer2.join();
consumer3.join();
return 0;
}
其中
cv.wait(lck,[]{return !q.empty();});
等价于
while(q.empty()){
cv.wait(lck);
}