POSIX的扩展,允许select()或等效的进程终止



在POSIX中,当特定的子进程终止时,无法通过select/poll得到通知。你能得到的最接近的是SIGCHLD的信号处理程序,它与线程的交互很差,在解释语言中可能根本不可用,并且在任何子进程终止时唤醒你。进入系统特定扩展的领域,signalfd可以更容易地从主事件循环中字段SIGCHLD,但不能完全解决线程问题或解释语言问题,并且当任何子进程终止时,它会再次唤醒您;我不知道还有谁能解决这个问题。

Unix的任何现代化身是否提供了一种机制,当特定子进程终止时,可以以100%无种族和线程安全的方式从对selectpoll或类似(epoll、kqueue…)的调用中唤醒您?

您是否控制或以其他方式信任子进程映像,从而可以假设它们而不是篡改继承的资源?

让每个子级继承特定于该子级的pipe对的写端。父级拥有每对的读取端,并先验地知道哪个fd与每个子级相关联。当一个子项终止时,读取结束表示一个挂起的EOF,对于select/poll/etc来说变得"可读"。即使在古老的Unix上,也应该能工作,在解释语言中,你可能无法选择它们的本地SIGCHLD处理。

另外,您可以在现代系统上实现您想要的东西,在指定处理(或接受)所有SIGCHLD的父系统中使用单个线程。然后,该线程必须将获得的PID转换为其他一些线程间通信,如I/O或条件变量。这不是小事,但它可以在无种族和线程安全的情况下完成。(如果你已经在混合线程和fork,我推断你无论如何都在采取一些预防措施。)

我如何才能以无种族的方式等待特定子代的终止

以下是以下情况下的可能选项列表:

  • 你无法控制孩子
  • 您无法控制整个父代码(例如,您正在编写库)和:

    • 无法设置全局SIGCHLD处理程序
    • 无法获取任何应该由父级中的其他代码处理的信号

首选解决方案

如果您已经在使用select()poll(),您可以将其替换为pselect()ppoll(),以同时等待I/OSIGCHLD

如果呼叫被SIGCHLD中断,您可以随后为每个受监控的子级呼叫非阻塞waitpid()

即使为SIGCHLD启用了SA_RESTART,这也会起作用,因为(p)select()(p)poll()从未重新启动。


其他选项

  1. 您可以在单独的线程中对waitpid()waitid()进行阻塞调用,这将等待特定的子线程,然后,例如,将消息写入管道
  2. 您可以将子进程放入不同的进程组,并在一个调用中等待多个子进程
  3. 如果不能为每个子级创建线程,则可以创建单个线程,该线程循环调用sigsuspend()以等待SIGCHLD(不需要获取),然后为每个受监控的子级调用非阻塞waitpid()

票据

请注意,使用signalfd,就像设置全局SIGCHLD处理程序一样,可能会影响父级中的其他代码,因为您可以获取其他人希望处理的信号。

最新更新