[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