[c] Linux에서 다중 스레드를 사용한 신호 처리

Linux에서 프로그램 (여러 스레드가있을 수 있음)이 SIGTERM 또는 SIGHUP와 같은 신호를 수신하면 어떻게됩니까?

어떤 스레드가 신호를 가로 챕니까? 여러 스레드가 동일한 신호를받을 수 있습니까? 전적으로 신호 처리 전용 특수 스레드가 있습니까? 그렇지 않은 경우 신호를 처리하는 스레드 내부에서 어떤 일이 발생합니까? 신호 처리기 루틴이 완료된 후 실행이 어떻게 재개됩니까?



답변

사용중인 Linux 커널 버전에 따라 약간의 차이가 있습니다.

2.6 posix 스레드를 가정하고 SIGTERM 또는 SIGHUP를 보내는 OS에 대해 이야기하는 경우 신호는 프로세스로 전송되며 루트 스레드에 의해 수신되고 처리됩니다. POSIX 스레드를 사용하면 SIGTERM을 개별 스레드에도 보낼 수 있지만 OS가 프로세스에 신호를 보낼 때 어떤 일이 발생하는지 묻는 것 같습니다.

2.6에서 SIGTERM은 자식 스레드가 “깨끗하게”종료되도록합니다. 2.4에서는 자식 스레드가 미정 상태로 남아 있습니다.


답변

pthreads(7) POSIX.1에는 다음을 포함하여 프로세스 공유 속성의 모든 스레드가 필요하다고 설명합니다.

  • 신호 처리

POSIX.1에서는 또한 다음을 포함하여 각 스레드에 대해 구별되는 몇 가지 속성이 필요합니다 .

Linux 커널의 complete_signal루틴에는 다음 코드 블록이 있습니다. 주석은 매우 유용합니다.

/*
 * 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_IGN또는로 설정 한 경우 SIG_DFL모든 스레드에 대해 신호가 무시됩니다 (또는 기본값-kill, core 또는 ignore).

프로세스가 신호의 처리를 특정 핸들러 루틴으로 설정 한 경우를 사용하여 특정 스레드 신호 마스크를 조작하여 신호를 수신 할 스레드를 제어 할 수 있습니다 pthread_sigmask(3). 하나의 스레드를 지정하여 모두 관리하거나 신호 당 하나의 스레드를 생성하거나 특정 신호에 대해 이러한 옵션을 혼합하여 생성하거나, 신호를 메인 스레드에 전달하는 Linux 커널의 현재 기본 동작에 의존 할 수 있습니다.

그러나 일부 신호는 signal(7)man 페이지 에 따르면 특별 합니다.

프로세스 전체 (예 : kill (2)를 사용하여 전송 된 경우 ) 또는 특정 스레드 (예 : SIGSEGV 및 SIGFPE와 같은 특정 신호, 실행의 결과로 생성됨 )에 대해 신호가 생성 (따라서 보류 중) 될 수 있습니다. 특정 기계어 명령어는 pthread_kill (3)을 사용하여 특정 스레드를 대상으로하는 신호와 마찬가지로 스레드 지시입니다
. 프로세스 지시 신호는 현재 신호가 차단되지 않은 스레드 중 하나로 전달 될 수 있습니다. 둘 이상의 스레드에서 신호가 차단 해제 된 경우 커널은 신호를 전달할 임의의 스레드를 선택합니다.


답변