Koncept zámků pro čtení a zápis je jednoduchý – umožňuje více vláken získávat zámky čtení současně, ale pouze jedno vlákno může současně získat zámky pro zápis, proto se tomu také říká sdílené exkluzivní zámky. V C# se doporučuje použít třídu ReaderWriterLockSlim k dokončení funkce uzamčení čtení/zápisu. V některých případech je počet čtení objektu mnohem větší než počet úprav, a pokud je objekt pouze zamčen, ovlivní to efektivitu čtení. Pokud je použit zámek čtení-zápis, může objekt číst více vláken současně a bude blokován pouze tehdy, když je objekt obsazen zápis-zámkem. Jednoduše řečeno, když vlákno vstoupí do režimu čtení, ostatní vlákna mohou stále přejít do režimu čtení, pokud vlákno chce v tuto chvíli vstoupit do režimu zápisu, musí být zablokováno. dokud režim čtení neukončí. Podobně, pokud vlákno přejde do režimu zápisu, ostatní vlákna budou zablokována, ať už chtějí psát nebo číst. Existují 2 způsoby, jak vstoupit do režimu zápisu/čtení: EnterReadLock se pokouší vstoupit do stavu uzamčení v režimu zápisu. TryEnterReadLock(Int32) se snaží vstoupit do stavu uzamčení režimu čtení s možností zvolit celočíselný timeout. EnterWriteLock se pokouší vstoupit do stavu Write Mode Lock. TryEnterWriteLock(Int32) se snaží vstoupit do stavu uzamčení v režimu zápisu a lze zvolit čas vypršení času. Existují 2 způsoby, jak opustit režim zápisu/čtení: ExitReadLock snižuje rekurzivní počet v režimu čtení a opouští režim čtení, když je výsledný počet 0 (nula). ExitWriteLock snižuje rekurzivní počet zápisového vzoru a opouští zápisový režim, když je výsledný počet 0 (nula). Tady je, jak ho používat:
Vidíte, že vlákna 3 a 4 mohou přejít do režimu čtení současně, zatímco vlákno 5 může přejít do režimu zápisu po 5 sekundách (tedy po opuštění zámku čtení vláken 3 a 4). Upravte výše uvedený kód, nejprve otevřete 2 vlákna v režimu zápisu a poté otevřete vlákna v režimu čtení, kód je následující:
Výsledky jsou následující:
Jak vidíte, vlákno 3 a vlákno 4 vstupují do režimu zápisu, ale vlákno 3 obsadí zápis jako první, takže vlákno 4 musí počkat 10 sekund, než vstoupí. Vlákna 5 a 6 musí obsadit zámek čtení, takže počkejte, až vlákno 4 opustí zápisový zámek, než pokračujete. TryEnterReadLock a TryEnterWriteLock mohou nastavit časový limit, při spuštění této věty vlákno zde zablokuje, pokud lze zámek v tomto okamžiku obsadit, pak vraťte true, pokud timeout ještě není obsazen zámkem, pak vraťte nepravdivé, vzdáte se obsazení zámku a pokračujte v přímém provádění následujícího kódu. VstupteUpgradeableReadLock Třída ReaderWriterLockSlim poskytuje upgradovatelný režim čtení, který se liší od režimu čtení tím, že jej lze také upgradovat do režimu zápisu voláním metod EnterWriteLock nebo TryEnterWriteLock. Protože v daném upgradovatelném režimu může být v jednom případě jen jedno vlákno. Vlákno, které vstoupí do upgradovatelného režimu, neovlivní vlákno v režimu čtení, tedy když vlákno přejde do upgradovatelného režimu, může libovolný počet vláken přejít do režimu čtení současně bez blokování. Pokud už více vláken čeká na získání zápisového zámku, spuštění EnterUpgradeableReadLock zablokuje, dokud tato vlákna nevyprší nebo neukončí zápisový zámek. Následující kód ukazuje, jak upgradovat na zápisový zámek v upgradovatelném režimu čtení.
Dopad zámků čtení/zápisu na výkon je zřejmý. Následující testovací kód:
Výše uvedený kód simuluje provoz 500 úloh, z nichž každé zabírá vlákno ve vlákně, z nichž 20 jsou vlákna pro zápis a 480 vláken pro čtení. Čtení dat trvá 10 ms a zápis 100 ms, aby se otestovala metoda zámku a metoda ReaderWriterLockSlim. Lze odhadnout, že pro ReaderWriterLockSlim lze odhadnout, že při čtení současně 480 vláken zabere 10 ms, 20 zápisových operací zabírá 2000ms, takže čas spotřebovaný je 2010ms, a u běžné metody zámku, protože jsou všechny exkluzivní, takže 480 čtení operací zabírá 4800ms + 20 zápisových operací 2000ms = 6800ms. Výsledky ukázaly znatelné zlepšení výkonu.
|