Záznam v POSIX o "Generování a doručování signálu" v "Rationale:System Interfaces General Information" říká
Signály generované pro proces jsou dodávány pouze do jednoho vlákna. Pokud je tedy více než jedno vlákno způsobilé pro příjem signálu, je třeba vybrat jedno. Volba vláken je ponechána zcela na implementaci, a to jak pro umožnění co nejširšího rozsahu vyhovujících implementací, tak pro poskytnutí volnosti implementacím doručit signál do „nejjednoduššího možného“ vlákna, pokud by mezi různými vlákny byly rozdíly ve snadnosti doručení.
Z signal(7)
manuál v systému Linux:
Může být vygenerován signál (a tedy nevyřízený) pro proces jako celek (např. při odeslání pomocí
kill(2)
) nebo pro konkrétní vlákno (např. určité signály, jako je SIGSEGV a SIGFPE, generované v důsledku provádění konkrétní instrukce ve strojovém jazyce, jsou směrovány do vlákna, stejně jako signály cílené na konkrétní vlákno pomocípthread_kill(3)
). Procesně řízený signál může být doručen do kteréhokoli z vláken, které aktuálně nemají signál blokovaný. Pokud má více než jedno z vláken odblokovaný signál, pak jádro vybere libovolné vlákno, kterému signál doručí.
A v pthreads(7)
:
Vlákna mají odlišná nastavení alternativního zásobníku signálů. Nastavení alternativního zásobníku signálů nového vlákna se však zkopíruje z vlákna, které jej vytvořilo, takže vlákna zpočátku sdílejí alternativní zásobník signálů (opraveno v jádře 2.6.16).
Z pthreads(3)
manuál na systému OpenBSD (jako příklad alternativního přístupu):
Obslužné rutiny signálů jsou normálně spuštěny na zásobníku aktuálně prováděného vlákna.
(Momentálně nevím, jak se to řeší, když se na víceprocesorovém počítači spouští více vláken současně)
Starší implementace LinuxThread vláken POSIX umožňovala cílení signálů pouze na odlišná jednotlivá vlákna. Od pthreads(7)
v systému Linux:
LinuxThreads nepodporuje pojem procesně řízených signálů:signály lze odesílat pouze do konkrétních vláken.
Rozšířením přijaté odpovědi je zde praktičtější pohled, který jsem našel zde.
Podstata je následující:
Obslužné rutiny signálů jsou pro každý proces, ale masky signálu pro každé vlákno.
- Pokud tedy nainstalujeme/odinstalujeme obslužný program signálu (s signal() nebo sigaction()) na libovolné vlákno, ovlivní to všechny.
- Pokud proces obdrží signál, bude obsluha provedena pouze v jednom vlákně. Toto vlákno je mezi nimi pseudonáhodně vybráno, jehož maska signálu to přijímá. Moje experimenty ukazují, že je to vždy vlákno s nejmenším pid.
- Signály odeslané do libovolného vlákna jsou považovány za signály odeslané hlavnímu procesu. Pokud tedy vlákno dostane signál, je docela možné, že obsluhu spustí jiné vlákno. Nejlepší je, když to vidíme jako vlákna (označená
tid
s, ID vláken) by byly považovány za maskované procesy (označenépid
s) a signály odeslané dotid
budou předány jejichpid
. - Pro provedení obsluhy signálu je v jeho masce signálu automaticky maskováno dané číslo signálu. Je to proto, aby se zabránilo spuštění obslužného programu seskládaných signálů v shluku signálu. Toto lze změnit pomocí
SA_NODEFER
vlajkasigaction(...)
zavolejte. - (3) a (4) vedou k tomu, že v případě shluku signálu systém distribuuje obslužné programy signálů možná nejvíce paralelně.
- Pokud jsme však nastavili sigaction s
SA_NODEFER
, signál dostane vždy stejné vlákno a budou se skládat .