代码之家  ›  专栏  ›  技术社区  ›  Donal Fellows

POSIX线程和信号

  •  74
  • Donal Fellows  · 技术社区  · 14 年前

    我一直试图理解POSIX线程和POSIX信号如何交互的复杂性。特别是,我感兴趣的是:

    • 控制将信号发送到哪个线程的最佳方法是什么(假设它一开始不是致命的)?
    • 告诉另一个线程(可能实际上很忙)信号已到达的最佳方法是什么?(我已经知道从信号处理程序使用pthread条件变量是个坏主意。)
    • 如何安全地处理将信号传递给其他线程的信息?这需要在信号处理程序中发生吗?(我一般不想杀死其他线程;我需要一种更微妙的方法。)

    我正在研究如何转换 TclX 包支持线程,或者将其拆分,至少使一些有用的部分支持线程。信号是那些特别感兴趣的部分之一。

    4 回复  |  直到 8 年前
        1
  •  44
  •   pilcrow    9 年前
    • 控制哪根线最好的方法是什么 信号发送到?

    正如@zoli2k所指出的,显式地指定一个线程来处理您想要处理的所有信号(或一组具有特定信号责任的线程),这是一种很好的技术。

    • 告诉另一个线程的最佳方法是什么(实际上可能很忙) 信号到了吗?[…]
    • 如何安全地处理传递信号的信息 其他线程?这需要在信号处理程序中发生吗?

    我不会说“最好”,但我的建议是:

    封锁所有需要的信号 main ,以便所有线程都继承该信号掩码。然后,将特殊的信号接收线程设计为信号驱动的事件循环,将新到达的信号调度为 其他线程内通信

    最简单的方法是让线程在循环中接受信号,使用 sigwaitinfo or sigtimedwait . 然后线程以某种方式转换信号,可能广播 pthread_cond_t ,用更多的I/O唤醒其他线程,将命令排队到特定于应用程序的线程安全队列中,无论什么。

    或者,特殊线程可以允许将信号传递到信号处理程序,只有在准备好处理信号时才能取消对传递的屏蔽。(通过处理程序传递信号比通过 sigwait 然而,在这种情况下,接收器的信号处理程序执行一些简单的异步信号安全操作:设置 sig_atomic_t 旗子,呼叫 sigaddset(&signals_i_have_seen_recently, latest_sig) , write ()非阻塞字节 self-pipe 等等。然后,在其屏蔽的主循环中,线程将接收到的信号按上述方式发送给其他线程。

    ( 更新 @卡夫正确地指出 信号等待 方法优越。)

        2
  •  13
  •   Craig McQueen Dr. Watson    8 年前

    根据POSIX标准,所有线程都应该在系统上显示相同的PID并使用 pthread_sigmask() 您可以为每个线程定义信号阻塞屏蔽。

    由于每个PID只允许定义一个信号处理程序,所以我更喜欢在一个线程中处理所有信号并发送 pthread_cancel() 如果需要取消正在运行的线程。这是对抗 pthread_kill() 因为它允许为线程定义清理函数。

    在一些较旧的系统上,由于缺少适当的内核支持,正在运行的线程可能具有与父线程的PID不同的PID。参见常见问题解答,了解信号处理 linuxThreads on Linux 2.4

        3
  •  4
  •   user2173833    12 年前

    imho、unix v信号和posix线程不能很好地混合。 Unix V是1970年的。posix是1980年;)

    有取消点,如果您允许信号和pthreads在一个应用程序中,您最终将围绕每个调用编写循环,这会意外地返回eintr。

    因此,在我必须在Linux或QNX上编写多线程程序的(少数)情况下,我所做的就是屏蔽所有(除了一个)线程的所有信号。

    当一个unix v信号到达时,进程切换堆栈(在unix v中,这与在进程中获得的并发性一样多)。

    正如这里的其他帖子提示的那样,现在可以告诉系统哪个POSIX线程将成为堆栈切换的受害者。

    一旦,您成功地使信号处理程序线程工作,问题仍然存在,如何将信号信息转换为文明的东西,其他线程可以使用。需要线程间通信的基础结构。一种模式非常有用,它是参与者模式,其中每个线程都是一些进程内消息传递机制的目标。

    因此,您不应该取消其他线程或杀死它们(或其他奇怪的东西),而是尝试将信号从信号上下文整理到信号处理程序线程,然后使用参与者模式通信机制向需要该信号的参与者发送语义上有用的消息。相关信息。

        4
  •  3
  •   Donal Fellows    14 年前

    到目前为止我所处的位置:

    • 信号来自不同的主要类,其中一些类通常只会杀死进程(sigill),而其中一些类则不需要做任何事情(sigio;更容易只做异步IO)。这两个班不需要行动。
    • 有些信号不需要立即处理;像sigwing这样的信号可以排队等待,直到方便为止(就像x11中的事件)。
    • 棘手的问题是,你想通过打断你正在做的事情来回应他们,但又不至于抹掉一根线。特别是,交互模式中的sigint应该让事物保持响应。

    我还得整理一下 signal VS sigaction , pselect , sigwait , sigaltstack 以及一大堆其他的POSIX(和非POSIX)API的位和块。