[OSy] Dotaz k ukončování vláken a konzistenci
Martin Decky
decky at d3s.mff.cuni.cz
Thu Jan 30 16:22:36 CET 2014
Hezký den,
> v našem týmu proběhla diskuze ohledně ukončování vláken a procesů a konzistence sdíleného stavu.
>
> Je nám jasné, že libovolné ukončování uživatelských vláken pomocí kill nebo thread_cancel nesmí způsobit nekonzistenci nebo úniky paměti v kernelu.
>
> Je ale nutné zajistit konzistenci např. uživatelské haldy? Pokud uživatelské vlákno mění uživatelskou haldu, je halda samozřejmě chráněna mutexem, ale pokud je vlákno zabito uvnitř kritické sekce, pak halda může zůstat pro zbytek procesu nekonzistentní.
> Možné řešení by bylo omezit místa, kde může být uživatelské vlákno zabito (cancellation points), ovšem potom nelze zaručit, že se vlákno povede zrušit (pokud běží ve smyčce bez cancellation points).
>
> Podobný problém je s kernelovými vlákny a funkcí thread_kill. V našem kernelu ji používáme pouze na zabíjení uživatelských vláken, takže takový problém nastat nemůže, ale pokud bychom chtěli zajistit korektní chování thread_kill i na kernelová vlákna (přestože takové užití v kernelu není), museli bychom zacházet se sdílenými daty opatrněji, a např. ochrana sdílených dat mutexem by nikdy nebyla dostatečná.
Myslím, že si kladete velmi správné otázky a také problematiku celkem
podrobně analyzujete.
Skutečnost je opravdu taková, že záležitosti násilného ukončování vláken
v souvislosti s jejich zdroji a konzistencí datových struktur nemá
jediné správné řešení. Různé varianty řešení potom mají různé
vlastnosti, výhody a nevýhody a pochopitelně se také mohou lišit v tom,
kdo nese odpovědnost na konzistenci celkového stavu.
Je tedy na Vašem uvážení, pro kterou variantu se v implementaci
rozhodnete. Důležité je, aby zvolená varianta byla logická, konzistentní
se zbytkem systému a pochopitelně také dobře zdokumentovaná.
Osobně (aniž bych Vás chtěl nějak ovlivnit) bych ve svých úvahách
vycházel z toho, že metoda thread_cancel() není určena pro řízené
rutinní ukončování vlákna (k tomu by měl v každém konkrétním případě
sloužit nějaký high-level mechanismus typu posílání zpráv, indikace
příznakem, synchronizačním primitivem apod.). Metoda thread_cancel()
slouží jako poslední (zoufalý) pokus, jak "odstřelit" libovolné
neposlušné vlákno a tudíž by měla fungovat vždy a ne pouze v
cancellation points. To ale pochopitelně znamená, že odpovědnost za
následky je na straně volajícího, včetně rizika vzniku nekonzistentního
globálního stavu procesu.
Úvaha pro kernel space musí být pochopitelně trochu jiná. Syscall, který
realizuje uživatelské volání thread_cancel(), by neměl nikdy způsobit
vznik nekonzistentního stavu kernelu, i za tu cenu, že bude blokující.
Kernel by měl být současně navržen pokud možno tak, aby toto blokování
nebylo neomezené.
(V případě volání thread_kill() bezprostředně přímo v kernelu však platí
stejná úvaha jako výše -- kernel se z principu nemůže proti chybě ve
vlastním kódu vždy ubránit.)
> Dále bychom se chtěli zeptat, zda je přípustné, právě kvůli hrozbě asynchronního ukončení vlákna, nebo konkurentního zrušení objektu, se kterým má syscall pracovat, po dobu syscallu zamknout mutex nebo zakázat přerušení.
Zamykání mutexu nebo zakazování přerušení (předpokládám během celé doby
provádění syscallu) není příliš elegantní řešení. Je to onen nechvalně
známý big kernel lock a na dnešním masivně paralelním hardwaru to
skutečně není didakticky správný postup :)
Konzistenci a správnou životnost identifikátorů objektů lze jistě
zaručit i při použití jemnější synchronizace. To samozřejmě může
znamenat, že se budete muset zamýšlet nad "zombie" stavy objektů, kdy a
jak bezpečně recyklovat identifikátory objektů atd.
M.D.
More information about the NSWI004
mailing list