Signalbehandlung mit mehreren Threads in Linux

Lesezeit: 4 Minuten

Was passiert unter Linux, wenn ein Programm (das möglicherweise mehrere Threads hat) ein Signal wie SIGTERM oder SIGHUP empfängt?

Welcher Thread fängt das Signal ab? Können mehrere Threads dasselbe Signal erhalten? Gibt es einen speziellen Thread, der ausschließlich dem Umgang mit Signalen gewidmet ist? Wenn nicht, was passiert innerhalb des Threads, der das Signal verarbeiten soll? Wie wird die Ausführung fortgesetzt, nachdem die Signalbehandlungsroutine beendet ist?

Benutzeravatar von sarnold
Sarnold

pthreads(7) beschreibt, dass POSIX.1 alle Threads in einem Prozess Share-Attribute erfordert, einschließlich:

  • signalisierungen

POSIX.1 erfordert auch einige Attribute unterscheidbar für jeden Thread, einschließlich:

Die des Linux-Kernels complete_signal Routine hat den folgenden Codeblock – die Kommentare sind sehr nützlich:

/*
 * 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
                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.
         */

Das sieht man also Sie sind dafür verantwortlich, wohin die Signale geliefert werden:

Wenn Ihr Prozess eine Signaldisposition gesetzt hat SIG_IGN oder SIG_DFLdann wird das Signal für alle Threads ignoriert (oder standardmäßig — kill, core oderignore).

Wenn Ihr Prozess die Disposition eines Signals auf eine bestimmte Behandlungsroutine festgelegt hat, können Sie steuern, welcher Thread die Signale empfängt, indem Sie bestimmte Thread-Signalmasken mit manipulieren pthread_sigmask(3). Sie können einen Thread ernennen, um sie alle zu verwalten, oder einen Thread pro Signal oder eine beliebige Mischung dieser Optionen für bestimmte Signale erstellen, oder Sie verlassen sich auf das aktuelle Standardverhalten des Linux-Kernels, das Signal an den Haupt-Thread zu liefern.

Einige Signale sind jedoch speziell nach der signal(7) Manpage:

Ein Signal kann für einen Prozess als Ganzes generiert (und somit anstehend) werden (z. B. wenn es mit gesendet wird töten (2)) oder für einen bestimmten Thread (z. B. sind bestimmte Signale, wie etwa SIGSEGV und SIGFPE, die als Folge der Ausführung einer bestimmten Maschinensprachanweisung erzeugt werden, Thread-gerichtet, ebenso wie Signale, die auf eine bestimmte Thread-Verwendung abzielen
pthread_kill(3)). Ein prozessgerichtetes Signal kann an jeden der Threads geliefert werden, bei dem das Signal derzeit nicht blockiert ist. Wenn mehr als einer der Threads das Signal entsperrt hat, wählt der Kernel einen beliebigen Thread, an den er das Signal liefert.

Dies ist leicht nuanciert, je nachdem, welche Version des Linux-Kernels Sie verwenden.

Unter der Annahme von 2.6 Posix-Threads und wenn Sie über das Betriebssystem sprechen, das SIGTERM oder SIGHUP sendet, wird das Signal an den Prozess gesendet, der vom Root-Thread empfangen und verarbeitet wird. Mit POSIX-Threads können Sie SIGTERM auch an einzelne Threads senden, aber ich vermute, Sie fragen, was passiert, wenn das Betriebssystem das Signal an den Prozess sendet.

In 2.6 bewirkt SIGTERM, dass untergeordnete Threads “sauber” beendet werden, während in 2.4 untergeordnete Threads in einem unbestimmten Zustand gelassen wurden.

  • Und was passiert im Root-Thread, wenn ein Signal empfangen wird? Nehmen wir an, ich habe einen benutzerdefinierten Signalhandler für SIGUSR1 geschrieben, und jetzt sende ich dieses Signal an den Prozess. Der Root-Thread erhält dieses Signal. Vielleicht ist es in diesem Moment mitten in einer Funktion. Was wird passieren?

    Benutzer500944

    26. Juli 2012 um 23:47 Uhr

  • Wenn Sie einen Handler eingerichtet haben, wird dieser als Interrupt behandelt und der Programmfluss wird angehalten und Ihr benutzerdefinierter Handler wird ausgeführt. Sobald es ausgeführt ist, kehrt die Kontrolle zurück, vorausgesetzt, Sie haben nichts getan, um den normalen Fluss zu ändern (Beenden usw.).

    – Alan

    26. Juli 2012 um 23:54 Uhr

  • Beachten Sie, dass dies spezifisch für SIGUSR1 ist, dessen IIRC Systemaufrufe nicht unterbricht. Wenn Sie dies beispielsweise mit SIGINT versucht haben, könnte es das Lesen eines Streams unterbrechen, und wenn Sie zum Lesen zurückkehren, gibt der Stream möglicherweise einen Fehler zurück, dass er unterbrochen wurde.

    – Alan

    27. Juli 2012 um 0:03 Uhr

  • Ich bin etwas verwirrt darüber, was mit “Root Thread” gemeint ist. Bedeutet dies, dass der Handler für SIGTERM immer im Hauptthread ausgeführt wird, oder kann er in jedem Thread ausgeführt werden?

    – Stefan Nutt

    1. Oktober 2014 um 21:18 Uhr

  • Diese Antwort, die besagt, dass ein beliebiger Thread zur Verarbeitung des Signals ausgewählt wird, widerspricht Ihrer Antwort.

    – Benutzer202729

    11. Januar 2019 um 10:08 Uhr


1423830cookie-checkSignalbehandlung mit mehreren Threads in Linux

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy