Lukk¶
Lõimedel on ühine mäluruum — seetõttu jagavad nad samu lokaalseid muutujaid, faile jne. Kuna aga igal lõimel on oma ülesanne, võib tekkida race condition. Olukord, kus mitu lõime muudavad korraga sama muutuja väärtust.
2 lõime üritavad samal ajal pangakontole raha lisada = race condition:
lock = threading.Lock()
saldo = 0 # both threads take same intial value
def add_money(cash):
temp = saldo
temp += cash # both threads calculate new credit
saldo = temp # later thread overwrites earlier threads result
Tulemuseks vale saldo.
Selle vältimiseks kasuta lukku (threading.Lock())
.

Lock¶
Lukk teeb ühise ressursi vaid ühele lõimele korraga kättesaadavaks. Tekib „pudelikaela efekt“, sest teised lõimed ootavad ressursi vabanemist. Maksimaalne kiirus on piiratud ühe lõime töökiirusega.
acquire
ja release
on asendatavad with
märkmesõnaga ehk context manager-iga.
Meetodid¶
acquire(blocking=True, timeout=-1)
: ressursi lukustamineblocking=True
ootab ressurssi vabanemist, et lukustada.timeout=-1
ootab piiramatu aja ressursi vabanemist.
Hoiatus
Korraga ei tohi olla
blocking=False
jatimeout
väärtustatud.
release()
- luku äravõtmine ressursilt / ressursi vabastamine
Kuigi ressurssi võib iga lõim vabastada, on soovitatav, et lukustaja lõim seda ise teeks.
Lukk ``blocking=False`` korral:
lock = threading.Lock()
def worker():
if lock.acquire(blocking=False):
try:
print("Got resource, now I can work")
finally:
lock.release()
# lock.release() # -> RuntimeError, because not locked
else:
print("Resource already locked, I will skip this step")
locked(): kas ressurss on hetkel lukus
RLock (reentrant lock)¶
Võimaldab lõimele sama lukku järjest kasutada. RLock
-i loendur tagab, et lukk vabastatakse nii mitu korda, kui sellega lukustatakse.
Kasutusjuhud:¶
Ühes meetodis teise meetodi kutsumine, kus kasutatakse sama lukku:
lock = threading.RLock()
def func_a():
with lock:
print("inside func A")
func_b()
def func_b():
with lock:
print("inside func B")
Alternatiiv mitme luku loomisele.
Lukustamine rekursiivses funktsioonis:
def rec(n, shared, lock):
with lock:
shared.append(n)
if n > 0:
rec(n-1, shared, lock)
shared = []
lock = threading.RLock()
rec(3, shared, lock)
print(shared) # [3, 2, 1, 0]
Sama luku väljakutsumine kõigepealt public ja siis private nähtavusega funktsioonis:
class Counter:
def __init__(self):
self.lock = threading.RLock() # public variable
self._value = 0 # private variable
def increase(self): # public method
with self.lock:
self._increase_step() # calls private helper
def _increase_step(self): # private method with shared lock
with self.lock:
self._value += 1
def get_value(self): # public method with shared lock
with self.lock:
return self._value