[python] Kriticka sekce (bylo RE: zamykani jednoho vlakna druhym)

Petr Prikryl PrikrylP na skil.cz
Čtvrtek Srpen 16 09:31:44 CEST 2007


Jen to trochu okomentuju...

Marek se ptal
> caute mam maly problem mam dve vlakna urobene cez 
> threading  a potrebujem jedno vlakno uzamknut 
> na chvilku druhym da sa to nejako?

Jirka se snažil (neberte mu to, většina se na to vy...)
> Nevim co znamena "uzamknout" a nikdy jsem neresil 
> podobny problem, ale vzhledem k tomu ze vlakna 
> sdileji globalni promenne by nemel byt problem 
> v jednom vlakne nastavit:
>
> vlakna_mutex = True
>
> a v druhem na vhodnem miste:
>
> while vlakna_mutex is True:
>    sleep(1)
>
> Tohle by bylo "brutalni reseni" ktere bych 
> zkusil jako prvni.

Karol zareagoval (má pravdu)
> takyto postup nemozno nazvat riesenie, ale hnusna "praktika" =>
> nespolahlive, nebezpecne, nepredvidatelne vysledky ... 
> Odporucam pozriet dokumentaciu [1] a clanok [2],
> pre lenivych:

Jirka si sype popel...
> Nojo, ja jsem si rikal ze nemam odpovidat na dotaz 
> kdyz si nejsem jisty odpovedi (a nemam cas 
> to hledat). Mea culpa, omlouvam se. 

Teď ten komentář. Thready jsou (pseudo)paralelně běžící
činnosti, které sdílejí společný datový prostor. Od 
čistých procesů se liší právě tím sdílením paměti.

Paralelně běžící čisté procesy se musí chovat 
korektně vůči používaným prostředkům. Platí to i 
pro thready, které se navíc musí starat právě
o to sdílení paměti. Paměť je místem, o které
musí korektně soupeřit. Takže multithreading
může být z hlediska programátorského výhodný
v méně případech, než se na první pohled může zdát.
Pokud se mu dá vyhnout, je lepší se mu vyhnout.
Pokud se mu nedá vyhnout, je dobré vědět, že
korektní řešení mohou být obtížná.

Při sdílení prostředku je nutné zajistit
výlučný přístup. K používání prostředku dochází
v úseku kódu, kterému se říká kritická sekce.
Kritická je proto, protože pokud by se více
procesů dostalo současně do odpovídající kritické
sekce, nastala by "kritická situace". Mohou nastat
v zásadě dva typy havárií deadlock (smrtelné
objetí -- všichni jsou mrtví) a race (vyhladovění
-- jeden se furt nemůže dostat k lizu, i když
něco furt jede).

Obvykle uvažujeme tak, že všechny paralelně 
běžící procesy mají stejné postavení. Musí se tedy
použít nástroj, který jim umožní dohodu.
Příslušná operace, pomocí které se rozhodnutí
o vstupu do kritické sekce realizuje, musí být
atomická (nedělitelná, nepřerušitelná). Proto
k tomu nelze využít prostředků o které soupeříme.
Proto nelze k rozhodnutí o použití sdílené
paměti využít jen obyčejné příkazy a kousek
sdílené paměti.

Dynamické čekání (v cyklu) je vždycky na prd, 
protože zatěžuje procesor. Proces se musí nechat
uspat (zablokovat) na dobu, kdy nemůže pracovat.
Z pohledu procesu je to ale aktivita typu 
"Před chvílí jsem usnul, ale právě jsem se 
vzbudil a jedu dál. Ani nevím, jak dlouho
jsem spal. Byl to jen okamžíček... (?)"

Pokud bych chtěl k vzájemnému vyloučení
procesů použit obyčejné příkazy a obyčejnou
sdílenou proměnnou, nedosáhnu atomického
chování:

    # Chybný pokus o realizaci kritické sekce.
    while blokováno:     # (1)
        pass
 
    blokováno = True     # (2)

    # Tohle je kód kritické sekce.
    příkaz1
    příkaz2
    ...

    # Tady jako opustím kritickou sekci.
    blokováno = False    # (3)

Jenže... Dejme tomu, že budu mít 3 thready
provádějící uvedený kód. Jeden s nich 
se právě nachází v naší "kritické sekci.
Dejme tomu, že ostatní dva do ní právě chtějí
vstoupit. Trčí dynamicky v cyklu (1).

Až dosud to může být zdánlivě vpořádku.
Když ale ten jeden opustí příkazem (3)
kritickou sekci, může dojít k tomu, že 
se ostatní thready prostřídají v činnosti
tak, že oba propadnou přes cyklus (1)
a teprve pak se dostanou k provádění (2).
Je to právě tím, že (1) a (2) se neprovedou 
atomicky, najednou, neoddělitelně.
Oba thready tedy vlezou do kritické sekce,
a myslí si, že v ní není nikdo jiný, což je
chyba.

Zjednodušeně řečeno, je to stejné, jako
kdybychom se nezatěžovali podobnými kličkami
a psali to úplně tupě. Jen se sníží pravděpodobnost
toho, že ta situace nastane, ale tím se současně
zvýší obtížnost odhalování příčin problémů, 
které se v budoucnu vyskytnou. Jinými slovy, 
problém nebudeme hledat v tomto místě, protože
si myslíme, že jsme to ošetřili a "musí" 
to fungovat.

pepr



Další informace o konferenci Python