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


119

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

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

답변:


35

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

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

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


그리고 신호가 수신되면 루트 스레드 내부에서 어떤 일이 발생합니까? SIGUSR1에 대한 사용자 지정 신호 처리기를 작성했으며 이제 해당 신호를 프로세스에 보내고 있다고 가정 해 보겠습니다. 루트 스레드는 해당 신호를받습니다. 아마도 그 순간 어떤 기능의 중간에있을 것입니다. 무슨 일이 일어날까요?

1
핸들러 설정이있는 경우 인터럽트로 처리되고 프로그램 흐름이 중지되고 사용자 정의 핸들러가 실행됩니다. 일단 실행되면 정상적인 흐름 (종료 등)을 변경하기 위해 아무것도하지 않았다고 가정하고 제어가 반환됩니다.
Alan

이것은 IIRC가 시스템 호출을 중단하지 않는 SIGUSR1에만 해당됩니다. 예를 들어 SIGINT로 이것을 시도하면 스트림 읽기가 중단 될 수 있으며 읽기로 돌아 갔을 때 스트림이 중단되었다는 오류를 반환 할 수 있습니다.
Alan

10
"루트 스레드"가 의미하는 바에 대해 약간 혼란 스럽습니다. 이것은 SIGTERM의 핸들러가 항상 메인 스레드에서 실행된다는 것을 의미합니까, 아니면 모든 스레드에서 실행될 수 있습니까?
Stephen Nutt 2014 년

3
이 답변 은 신호를 처리하기 위해 임의의 스레드가 선택되었음을 나타내며 답변 과 모순됩니다.
user202729

135

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)을 사용하여 특정 스레드를 대상으로하는 신호와 마찬가지로 스레드 지시입니다 . 프로세스 지시 신호는 현재 신호가 차단되지 않은 스레드 중 하나로 전달 될 수 있습니다. 둘 이상의 스레드에서 신호가 차단 해제 된 경우 커널은 신호를 전달할 임의의 스레드를 선택합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.