Gestione del segnale con più thread in Linux


119

In Linux, cosa succede quando un programma (che possibilmente ha più thread) riceve un segnale, come SIGTERM o SIGHUP?

Quale thread intercetta il segnale? Possono più thread ottenere lo stesso segnale? Esiste un thread speciale dedicato interamente alla gestione dei segnali? In caso contrario, cosa succede all'interno del thread che deve gestire il segnale? Come riprende l'esecuzione al termine della routine del gestore del segnale?

Risposte:


35

Questo è leggermente sfumato, in base alla versione del kernel Linux che stai utilizzando.

Assumendo 2.6 thread posix e se stai parlando del sistema operativo che invia SIGTERM o SIGHUP, il segnale viene inviato al processo, che viene ricevuto e gestito dal thread root. Utilizzando i thread POSIX, puoi anche inviare SIGTERM anche a singoli thread, ma sospetto che tu stia chiedendo cosa succede quando il sistema operativo invia il segnale al processo.

In 2.6, SIGTERM farà sì che i thread figli escano "in modo pulito", dove come 2.4, i thread figli erano lasciati in uno stato indeterminato.


E cosa succede all'interno del thread principale quando viene ricevuto un segnale? Diciamo che ho scritto un gestore di segnale personalizzato per SIGUSR1 e ora sto inviando quel segnale al processo. Il thread principale riceverà quel segnale. Forse è nel mezzo di qualche funzione in quel momento. Cosa succederà?

1
se si dispone di una configurazione del gestore, verrà trattata come un interrupt e il flusso del programma verrà interrotto e verrà eseguito il gestore personalizzato. Una volta eseguito, il controllo tornerà, assumendo che tu non abbia fatto nulla per alterare il flusso normale (uscita, ecc.).
Alan

Notare che questo è specifico per SIGUSR1, che IIRC non interrompe le chiamate di sistema. Se hai provato questo con SIGINT, ad esempio, potrebbe interrompere la lettura di un flusso e quando sei tornato alla lettura, il flusso potrebbe restituire un errore che è stato interrotto.
Alan,

10
Sono un po 'confuso su cosa si intende per "thread radice". Ciò significa che il gestore di SIGTERM verrà sempre eseguito nel thread principale o può essere eseguito in qualsiasi thread?
Stephen Nutt

3
Questa risposta , che afferma che un thread arbitrario viene scelto per gestire il segnale, contraddice la tua risposta.
user202729

134

pthreads(7) descrive che POSIX.1 richiede tutti i thread in attributi di condivisione del processo, inclusi:

  • disposizioni del segnale

POSIX.1 richiede anche che alcuni attributi siano distinti per ogni thread, tra cui:

La complete_signalroutine del kernel Linux ha il seguente blocco di codice: i commenti sono piuttosto utili:

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

Quindi, vedi che sei responsabile di dove vengono consegnati i segnali:

Se il processo ha impostato la disposizione di un segnale su SIG_IGNo SIG_DFL, il segnale viene ignorato (o predefinito: kill, core o ignore) per tutti i thread.

Se il processo ha impostato la disposizione di un segnale su una routine di gestione specifica, è possibile controllare quale thread riceverà i segnali manipolando maschere di segnali di thread specifiche utilizzando pthread_sigmask(3). È possibile nominare un thread per gestirli tutti, o creare un thread per segnale, o qualsiasi combinazione di queste opzioni per segnali specifici, oppure fare affidamento sull'attuale comportamento predefinito del kernel Linux di fornire il segnale al thread principale.

Alcuni segnali, tuttavia, sono speciali secondo la signal(7)pagina man:

Un segnale può essere generato (e quindi in sospeso) per un processo nel suo complesso (ad esempio, quando viene inviato utilizzando kill (2) ) o per un thread specifico (ad esempio, alcuni segnali, come SIGSEGV e SIGFPE, generati come conseguenza dell'esecuzione una specifica istruzione in linguaggio macchina è diretta ai thread, così come i segnali mirati a un thread specifico utilizzando pthread_kill (3) ). Un segnale diretto al processo può essere consegnato a uno qualsiasi dei thread che attualmente non ha il segnale bloccato. Se più di uno dei thread ha il segnale sbloccato, il kernel sceglie un thread arbitrario a cui inviare il segnale.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.