std::condition_variable::notify_one是可重入的吗?
Is std::condition_variable::notify_one reentrant?
我可以安全地执行以下代码吗?是否有可能在这里出现死锁或一些意外行为,尤其是当 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
| cv.wait(mtx, []{return flag;}):
| while(!flag)
flag = true |
cv.notify_one() | <--- this notification is lost
| cv.wait(mtx); <--- waits for the next notification
这是一个非常微妙但非常常见的编程错误。当条件变量经常被通知时,很难注意到丢失的通知和引入的延迟。只有当条件变量仅在问题变得明显时才通知。
条件变量没有状态,它们只是一种(干扰(通知机制,与 Windows 事件不同,这是一个混淆因素。
更新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();
}
请注意,必须在所有线程中阻止信号,以便只有信号处理程序线程接收这些信号。
相关文章:
- 我需要std::condition,但有两个以上的选择
- QT C++如何调用lambda one
- 为什么'allocate in one library and free in the other'是错误的
- C++ WinRT - XAudio2是否支持Xbox One平台
- 使用 Poco:Condition 唤醒两个线程
- 为什么我收到错误:"there is more than one default constructor"?
- g++ 在我尝试用 ONE LINE 编译程序时崩溃了
- 在 ONE 设置中添加附加包含目录并引用 => 指向静态库
- "Control reaches end on non-void function" with do { return result; } while(condition);
- 为什么海湾合作委员会声称我违反了"at least one argument for variadic macro",而我至少有一个论点?
- condition.wait_for智能感知错误
- 是-!(condition)从布尔值(mask-boolean)中获得完整位向量的正确方法
- "State pattern" vs "one member function per state" ?
- 编译时"one or more multiply defined symbols found"错误
- 如何在QxORM中定义具有多个主键的表,其中一个主键是与另一个表的"many to one"关系
- VS 编译器错误 C2752 ( "more than one partial specialization matches" ) 在 STL 中
- IF ELSE CONDITION
- one.cpp和two.cpp都包含两个.h
- 调用了基运算符而不是派生的one-Normal行为
- 如何使用多个 SVM 分类器(每个分类器都有一个特定的内核)作为"one vs rest classification"方案?