Reentrantní mutex - Reentrant mutex

V informatice je reentrantní mutex ( rekurzivní mutex , rekurzivní zámek ) konkrétním typem zařízení pro vzájemné vyloučení (mutex), které může být několikrát uzamčeno stejným procesem/vláknem , aniž by došlo k zablokování .

Zatímco jakýkoli pokus o provedení operace „uzamčení“ na běžném mutexu (zámku) by buď selhal, nebo by byl zablokován, když je již mutex uzamčen, na rekurzivním mutexu bude tato operace úspěšná tehdy a jen tehdy, pokud uzamykací vlákno je to, které již drží zámek. Rekurzivní mutex obvykle sleduje, kolikrát byl uzamčen, a vyžaduje, aby bylo provedeno stejně mnoho operací odemčení, než jej mohou uzamknout jiná vlákna.

Motivace

Rekurzivní mutexy řeší problém nereentrance s pravidelnými mutexy: pokud je funkce, která vezme zámek a provede zpětné volání, sama vyvolána zpětným voláním, dojde k zablokování . V pseudokódu je to následující situace:

var m : Mutex  // A non-recursive mutex, initially unlocked.

function lock_and_call(i : Integer)
    m.lock()
    callback(i)
    m.unlock()

function callback(i : Integer)
    if i > 0
        lock_and_call(i - 1)

lock_and_call(1)  // Invoking the function

Vzhledem k těmto definicím způsobí volání funkce lock_and_call (1) následující sled událostí:

  • m.lock () - mutex uzamčen
  • zpětné volání (1)
  • lock_and_call (0) - protože i> 0
  • m.lock () - zablokování, protože m je již uzamčeno, takže provádějící vlákno se zablokuje a čeká na sebe.

Výměna mutexu za rekurzivní problém vyřeší, protože finální m.lock () bude úspěšné bez blokování.

Praktické použití

W. Richard Stevens poznamenává, že rekurzivní zámky jsou „složité“ ke správnému používání, a doporučuje jejich použití pro přizpůsobení jednovláknového kódu beze změny API , ale „pouze tehdy, když není možné jiné řešení“.

Na Java jazyk je nativní synchronizační mechanismus, monitory , používá rekurzivní zámky. Syntakticky je zámek blok kódu, kterému předchází klíčové slovo „synchronizováno“ a jakýkoli odkaz na objekt v závorkách, který bude použit jako mutex. Uvnitř synchronizovaného bloku lze daný objekt použít jako proměnnou podmínky tím, že na něm provedete příkaz wait (), Notify () nebo NotifyAll (). Všechny objekty jsou tedy rekurzivní mutexy i proměnné podmínek .

Příklad

  1. Vlákno A volá funkci F, která pro sebe před pokračováním získá zámek reentrantů
  2. Vlákno B volá funkci F, která se pokouší získat pro sebe nový zámek, ale nemůže kvůli jednomu již nevyřešenému, což má za následek buď blok (čeká), nebo časový limit, je -li požadován
  3. F vlákno A se volá rekurzivně. Už zámek vlastní, takže se sám neblokuje (žádný zablokování). Toto je ústřední myšlenka reentrantního mutexu a čím se liší od běžného zámku.
  4. Závit B F stále čeká, nebo zachytil časový limit a pracoval kolem něj
  5. Závit A's F dokončí a uvolní zámek (y)
  6. F -vlákno B nyní může získat reentrantní zámek a pokračovat, pokud stále čeká

Emulace softwaru

Emulaci softwaru lze provést pomocí následující struktury:

  • Podmínka „ovládání“ pomocí běžného zámku
  • Identifikátor vlastníka, jedinečný pro každé vlákno (výchozí nastavení je prázdné / nenastaveno)
  • Počet akvizic (výchozí hodnota je nula)

Získávání

  1. Získejte kontrolní podmínky.
  2. Pokud je nastaven vlastník a ne aktuální vlákno, počkejte, až bude oznámena podmínka ovládání (tím se podmínka také uvolní).
  3. Nastavte vlastníka na aktuální vlákno. V tomto okamžiku měl být identifikátor vlastníka již vymazán, pokud nabyvatel již není vlastníkem.
  4. Zvyšte počet akvizic (u nových vlastníků by měl vždy vyústit v 1).
  5. Uvolněte kontrolní podmínku.

Uvolnění

  1. Získejte kontrolní podmínku s tvrzením, že uvolňovačem je vlastník.
  2. Snižte počet akvizic s tvrzením, že počet je větší nebo roven nule.
  3. Pokud je počet akvizic nula, vymažte informace o majiteli a upozorněte na kontrolní podmínku.
  4. Uvolněte kontrolní podmínku.

Reference