c++ - std::condition_variable::notify_one 是可重入的吗?
问题描述
我可以安全地执行以下代码吗?这里是否可能出现死锁或一些意外行为,尤其是当 SIGINT 到达时?
#include <atomic>
#include <condition_variable>
#include <csignal>
std::mutex m;
std::condition_variable cv;
std::atomic<bool> flag(false);
void f1(){
std::signal(SIGTERM, [](int signal){flag.store(true,
std::memory_order_release); cv.notify_one();});//register for signal
std::unique_lock<std::mutex> mtx(m);
cv.wait(mtx, []{return flag.load(std::memory_order_consume);});//wait for signal or f2() notify
}
void f2(){
flag.store(true, std::memory_order_release);
cv.notify_one();
}
int main(){
std::thread th1(f1);
std::thread th2(f2);
th1.join();
th2.join();
return 0;
}
解决方案
pthread
函数以及std::condition_variable
使用std::mutex
这些函数的函数不是异步信号安全的。请参阅 中的异步信号安全函数列表man signal-safety(7)
。
有点离题:如果您在更新时不锁定互斥锁flag
,则会导致错过通知。想象一下场景:
Thread 1 | Thread 2
| mutex.lock()
| flag == false
flag = true |
cv.notify_one() | <--- notification is lost
| cv.wait()
这是一个非常常见的编程错误。
更新时锁定互斥锁flag
可解决此问题。
如果您想在收到信号时通知条件变量,请创建一个专用于信号处理的线程。例子:
#include <condition_variable>
#include <iostream>
#include <thread>
#include <signal.h>
std::mutex m;
std::condition_variable cv;
bool flag = false;
void f1(){
std::unique_lock<std::mutex> lock(m);
while(!flag)
cv.wait(lock);
}
void signal_thread() {
sigset_t sigset;
sigfillset(&sigset);
int signo = ::sigwaitinfo(&sigset, nullptr);
if(-1 == signo)
std::abort();
std::cout << "Received signal " << signo << '\n';
m.lock();
flag = true;
m.unlock();
cv.notify_one();
}
int main(){
sigset_t sigset;
sigfillset(&sigset);
::pthread_sigmask(SIG_BLOCK, &sigset, nullptr);
std::thread th1(f1);
std::thread th2(signal_thread);
th1.join();
th2.join();
}
请注意,信号必须在所有线程中被阻塞,以便只有信号处理程序线程接收这些信号。
推荐阅读
- google-cloud-platform - 餐厅用餐选项(即堂食、外卖、外卖)是否有 Google Places API 返回字段?
- java - 如何使用 ValueEventListener 仅在添加新子代时生成 tost,而不为已存在的子代生成?有任何想法吗?
- ios - XCode 12 SwiftUI 找不到自动预览
- arrays - 找到网格的最小封闭区域
- objectgears - 识别 ObjectGears 中的错误查询
- ios - how to still show the progress of progressView after reloading the view controller?
- python - 如何确定 cross_validate 是否使用分层 K 折?
- c++ - C++ dll 和名称修改问题
- python-3.x - 如何使用 python 请求指定确切的 http 方法?
- list - Setstate 在小部件列表中不起作用