如何以异步信号安全的方式唤醒 macOS 中的线程?

问题描述 投票:0回答:1

我正在 macOS 上开发一个 GRPC 服务器应用程序。在此应用程序中,我需要处理 SIGINT 和 SIGTERM 以便正常终止。

通常,在 Linux 上,我会使用 POSIX 信号量,因为使用 POSIX 信号量进行等待和通知的函数是异步信号安全的。

但是,在 macOS 中,POSIX 信号量并未实现。我查看了其他可能使用的同步原语,并且偶然发现了

os_unfair_lock
,它看起来不错,但在文档中它没有声明它是异步信号安全的。

如何安全地让等待条件变量的线程从信号处理程序中唤醒,而不需要轮询原子变量(这会消耗 CPU)?

谢谢

编辑:应用程序采用 C/C++ 语言

multithreading macos signals thread-synchronization
1个回答
0
投票

我已经求助于使用

pipe()

  1. 在注册信号处理程序之前打开管道
  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);
  1. 从需要唤醒的线程中,我们可以直接调用
    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;
  }
}
  1. 从信号处理程序中,我们可以
    write
    到达管道。
    write
    系统调用是异步信号安全的:
void signalHandler(int signal) {
  write(pipeFD, "EXIT", 4);
}

这样就可以了。用户可以根据

pipe(2)
验证管道发送的数据是否有效,当两个文件描述符都关闭时,任何剩余数据都将被丢弃。

© www.soinside.com 2019 - 2024. All rights reserved.