【问题标题】:Signal handling with multiple threads in LinuxLinux 中多线程的信号处理
【发布时间】:2012-07-25 15:30:05
【问题描述】:

在 Linux 中,当一个程序(可能有多个线程)接收到一个信号(如 SIGTERM 或 SIGHUP)时会发生什么?

哪个线程拦截了信号?多个线程可以得到相同的信号吗?是否有专门用于处理信号的特殊线程?如果不是,处理信号的线程内部会发生什么?信号处理程序完成后如何恢复执行?

【问题讨论】:

    标签: c linux multithreading signals ipc


    【解决方案1】:

    pthreads(7) 描述了 POSIX.1 要求一个进程中的所有线程共享属性,包括:

    • 信号配置

    POSIX.1 还要求每个线程的某些属性不同,包括:

    Linux 内核的complete_signal 例程具有以下代码块——cmets 非常有用:

    /*
     * Now find a thread we can wake up to take the signal off the queue.
     *
     * If the main thread wants the signal, it gets first crack.
     * Probably the least surprising to the average bear.
     */
    if (wants_signal(sig, p))
            t = p;
    else if (!group || thread_group_empty(p))
            /*
             * There is just one thread and it does not need to be woken.
             * It will dequeue unblocked signals before it runs again.
             */
            return;
    else {
            /*
             * Otherwise try to find a suitable thread.
             */
            t = signal->curr_target;
            while (!wants_signal(sig, t)) {
                    t = next_thread(t);
                    if (t == signal->curr_target)
                            /*
                             * No thread needs to be woken.
                             * Any eligible threads will see
                             * the signal in the queue soon.
                             */
                            return;
            }
            signal->curr_target = t;
    }
    
    /*
     * Found a killable thread.  If the signal will be fatal,
     * then start taking the whole group down immediately.
     */
    if (sig_fatal(p, sig) &&
        !(signal->flags & SIGNAL_GROUP_EXIT) &&
        !sigismember(&t->real_blocked, sig) &&
        (sig == SIGKILL || !p->ptrace)) {
            /*
             * This signal will be fatal to the whole group.
             */
    

    因此,您会看到 负责信号的传递位置:

    如果您的进程已将信号的处置设置为 SIG_IGNSIG_DFL,则所有线程都会忽略该信号(或默认值 -- kill、core 或 ignore)。

    如果您的进程已将信号的处置设置为特定的处理程序例程,那么您可以通过使用pthread_sigmask(3) 操作特定的线程信号掩码来控制哪个线程将接收信号。您可以指定一个线程来管理所有这些,或者为每个信号创建一个线程,或者这些选项的任意组合用于特定信号,或者您依赖 Linux 内核当前将信号传递到主线程的默认行为。

    然而,根据signal(7) 手册页,有些信号是特殊的:

    可能会为整个进程生成(并因此挂起)信号 (例如,当使用 kill(2) 发送时)或针对特定线程(例如, 某些信号,例如 SIGSEGV 和 SIGFPE,生成为 执行特定机器语言指令的结果是 线程定向,针对特定线程的信号使用 pthread_kill(3))。一个过程导向的信号可以被传递到任何 当前没有阻塞信号的线程之一。 如果多个线程的信号被解除阻塞,则 内核选择一个任意线程来传递信号。

    【讨论】:

      【解决方案2】:

      这略有细微差别,具体取决于您使用的 Linux 内核版本。

      假设 2.6 posix 线程,如果你在谈论操作系统发送 SIGTERM 或 SIGHUP,信号被发送到进程,由根线程接收和处理。使用 POSIX 线程,您也可以将 SIGTERM 发送到各个线程,但我怀疑您是在询问操​​作系统向进程发送信号时会发生什么。

      在 2.6 中,SIGTERM 将导致子线程“干净地”退出,而在 2.4 中,子线程处于不确定状态。

      【讨论】:

      • 当收到信号时,根线程内部会发生什么?假设我为 SIGUSR1 编写了一个自定义信号处理程序,现在我将该信号发送到进程。根线程将获得该信号。也许那一刻它正处于某些功能的中间。会发生什么?
      • 如果您有一个处理程序设置,它将被视为一个中断,程序流程将停止,您的自定义处理程序将被执行。一旦它被执行,控制将会返回,假设你没有做任何事情来改变正常的流程(退出等)。
      • 请注意,这是特定于 SIGUSR1,IIRC 不会中断系统调用。例如,如果您尝试使用 SIGINT 进行此操作,它可能会中断流读取,当您返回读取时,流可能会返回一个错误,表明它已被中断。
      • 我对“根线程”的含义有些困惑。这是否意味着 SIGTERM 的处理程序将始终在主线程中运行,还是可以在任何线程中运行?
      • This answer,其中指出选择了任意线程来处理信号,这与您的回答相矛盾。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多