Minule jsme si ukázali využití příkazu with
při práci se soubory. Dneska se podíváme na to, jak jej využít při práci se zámky.
Původní kód
Vezměme si následující kód, který využívá zámky pro vzájemné vyloučení:
from threading import Lock lock = Lock() # ... lock.acquire() # Kritická sekce lock.release()
Nejdříve se provede zavolání lock.acquire()
, které zjistí, zda byl zámek již zamknut. Pokud ano, počká na jeho odemčení. Pokud ne, tak jej zamkne a vstoupí do kritické sekce, kde můžeme pracovat např. se sdílenými zdroji. Poté dojde k opuštění kritické sekce a odemčení zámku.
Proč takto raději ne?
Stejně jako minule, i zde nastane problém v případě, kdy během kritické sekce dojde k vyhození výjimky. V takovém případě se nezavolá lock.release()
a může dojít k zablokování. Řešení je nasnadě:
lock.acquire() try: # Kritická sekce finally: lock.release()
To je ale značně zdlouhavé. Navíc to neřeší to, že se nesmí zapomenout na zavolání lock.release()
.
Jak to udělat lépe?
Jak již bylo řečeno v úvodu, tak opět využijeme příkaz with
:
with lock: # Kritická sekce
Tento příkaz za nás automaticky zavolá lock.acquire()
, provede kód v kritické sekci, a poté zavolá lock.release()
, ať už došlo k vyhození výjimky či nikoliv. Nemusíme si tedy dělat starosti s odemčením zámku. Skvělé, že?