由于 C++ 信号处理程序只能访问 volatile std::sig_atomic_t 或 std::atomic(C++11 起),是否可以让线程休眠并随之唤醒?
std::atomic_bool exit_now(false);
void signal_handler(int signal)
{
exit_now=true;
}
int main() {
std::signal(SIGINT, signal_handler);
A a;
B b;
a.RunAsync();
b.RunAsync();
while(!exit_now)
std::this_thread::sleep_for(std::chrono::seconds(1));
a.Stop();
b.Stop();
return 0;
}
在这种情况下,A 和 B ::RunAsync() 都在其他线程上执行任务,直到我调用 ::Stop(),所以我唯一的选择是在主线程上忙等待(有或没有预定义的睡眠周期) ).
理想情况下,我希望主线程休眠直到收到信号,可能带有条件变量,但这看起来是非法的。
我建议(阻塞信号并)使用 sigwait(2) 在主线程中同步等待信号,然后你就完全避免了必须从信号处理程序到线程进行通信的问题。
您所追求的是一种以异步信号安全的方式唤醒线程的方法。
我在 Linux 中执行此操作的首选方法是使用 POSIX 信号量。请记住,这可能无法移植到其他操作系统,因为操作系统不需要 POSIX 信号量即可被视为符合 POSIX 标准。
// signalSemaphore is a global variable
if (sem_init(&signalSemaphore, 0, 0)) {
std::cerr << "Unable to initialise semaphore: " << strerror(errno);
return 1;
}
while(sem_wait(signalSemaphore)) {
if(errno != EINTR) {
// call can be interrupted, so if the error is EINTR we ignore it
std::cerr << "Error waiting for signal semaphore: " << strerror(errno);
}
}
sem_wait()
调用:void signalHandler(int signal) {
sem_post(&signalSemaphore);
}
或者,使用管道也是一种选择,因为
read()
和 write()
系统调用也是异步信号安全的,并且管道是一种更可移植的机制。请参阅此处有关如何执行此操作的示例:如何以异步信号安全的方式唤醒 macOS 中的线程?