我正在 macOS 上开发一个 GRPC 服务器应用程序。在此应用程序中,我需要处理 SIGINT 和 SIGTERM 以便正常终止。
通常,在 Linux 上,我会使用 POSIX 信号量,因为使用 POSIX 信号量进行等待和通知的函数是异步信号安全的。
但是,在 macOS 中,POSIX 信号量并未实现。我查看了其他可能使用的同步原语,并且偶然发现了
os_unfair_lock
,它看起来不错,但在文档中它没有声明它是异步信号安全的。
如何安全地让等待条件变量的线程从信号处理程序中唤醒,而不需要轮询原子变量(这会消耗 CPU)?
谢谢
编辑:应用程序采用 C/C++ 语言
我已经求助于使用
pipe()
。
int fds[2];
if(pipe(fds) != 0) {
LOG(ERROR) << "Unable to open pipe: " << strerror(errno) << std::endl;
return 1;
}
struct sigaction newAction;
newAction.sa_handler = signalHandler;
sigemptyset(&newAction.sa_mask);
newAction.sa_flags = 0;
sigaction(SIGINT, &newAction, NULL);
sigaction(SIGTERM, &newAction, NULL);
read()
并使用阻塞 IO 来避免浪费 CPU 周期。请记住,如果被信号中断,呼叫可能会返回,因此我们检查 EINTR
:ssize_t bytes_read = read(pipeFD, &msg, 4);
if(bytes_read == -1) {
if(errno != EINTR) {
LOG(ERROR) << "Error reading from pipe: " << strerror(errno) << std::endl;
exitFlag = true;
break;
}
}
write
到达管道。 write
系统调用是异步信号安全的:void signalHandler(int signal) {
write(pipeFD, "EXIT", 4);
}
这样就可以了。用户可以根据
pipe(2)
验证管道发送的数据是否有效,当两个文件描述符都关闭时,任何剩余数据都将被丢弃。