pthreads(7)
beschreibt, dass POSIX.1 alle Threads in einem Prozess Teilen Attributen erfordert, einschließlich:
- Signal Dispositionen erfordert
POSIX.1 auch einige Attribute deutliche für jeden Thread zu sein, einschließlich:
Der complete_signal()
Routine des Linux-Kernels hat den folgenden Code-Block - 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(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_UNKILLABLE | SIGNAL_GROUP_EXIT)) &&
!sigismember(&t->real_blocked, sig) &&
(sig == SIGKILL || !t->ptrace)) {
/*
* This signal will be fatal to the whole group.
*/
Also, Sie sehen, dass Sie sind verantwortlich für, wo Signale geliefert werden:
Wenn Sie Prozess hat die Signalverteilung auf SIG_IGN
oder SIG_DFL
festgelegt, dann wird das Signal für alle Threads ignoriert (oder default - kill, core oder ignore).
Wenn Ihr Prozess die Signalverteilung für eine bestimmte Handler-Routine festgelegt hat, können Sie steuern, welcher Thread die Signale empfängt, indem Sie bestimmte Thread-Signalmasken mit pthread_sigmask(3)
bearbeiten. Sie können einen Thread für die Verwaltung aller Threads nominieren oder einen Thread pro Signal oder eine Mischung dieser Optionen für bestimmte Signale erstellen oder Sie verlassen sich auf das aktuelle Standardverhalten des Linux-Kernels, das Signal an den Hauptthread zu liefern.
Einige Signale sind jedoch besondere:
A signal may be generated (and thus pending) for a process as
a whole (e.g., when sent using kill(2)) or for a specific
thread (e.g., certain signals, such as SIGSEGV and SIGFPE,
generated as a consequence of executing a specific machine-
language instruction are thread directed, as are signals
targeted at a specific thread using pthread_kill(3)). A
process-directed signal may be delivered to any one of the
threads that does not currently have the signal blocked. If
more than one of the threads has the signal unblocked, then
the kernel chooses an arbitrary thread to which to deliver
the signal.
Und was im Wurzelfaden passiert, wenn ein Signal empfangen wird? Nehmen wir an, ich habe einen benutzerdefinierten Signal-Handler für SIGUSR1 geschrieben, und jetzt sende ich dieses Signal an den Prozess. Der Root-Thread wird dieses Signal erhalten. Vielleicht ist es gerade in der Mitte einer Funktion. Was wird passieren? –
Wenn Sie ein Handler-Setup haben, wird es als Interrupt behandelt, und der Programmfluss wird angehalten und Ihr benutzerdefinierter Handler wird ausgeführt. Sobald es ausgeführt wird, kehrt die Steuerung zurück, vorausgesetzt, Sie haben nichts getan, um den normalen Ablauf zu ändern (Beenden usw.). – Alan
Beachten Sie, dass dies für SIGUSR1 spezifisch ist, wobei IIRC Systemaufrufe nicht unterbricht. Wenn Sie dies beispielsweise mit SIGINT versuchten, konnte es einen Stream-Lesevorgang unterbrechen, und wenn Sie zum Lesen zurückkehren, gibt der Stream möglicherweise einen Fehler zurück, der unterbrochen wurde. – Alan