У вас есть две ошибки.Первое упомянуто в ответе Соломона Слоу.Вы не удерживаете блокировку в течение всей операции чтения-изменения-записи.Как вы и предполагали, это можно исправить, передвинув блокировку вверх.
Но у вас есть другая проблема - никакая блокировка не защищает euro
.Каждый поток блокирует сам , позволяя каждому потоку захватить блокировку для себя и одновременно выполнять чтение-изменение-запись.
Чтобы исправить это, необходима специальная блокировка, которая защищаетeuro
и все операции над ним должны выполняться под защитой этого единственного замка.Для этого я добавил блокировку к Casino
.
Вот исправленный код:
import threading
import time
class Casino:
euro = 0
lock = threading.Lock();
class PlayingThread(threading.Thread):
def __init__(self, the_casino, playerno=1):
threading.Thread.__init__(self)
self.lock = threading.Lock()
self.playerno = playerno
self.the_casino = the_casino
def run(self):
time.sleep(2)
self.the_casino.lock.acquire()
tmp = self.the_casino.euro
time.sleep(1)
self.the_casino.euro = tmp + 1
self.the_casino.lock.release()
casino = Casino()
lt = []
for i in range(0, 5):
pt = PlayingThread(casino, i)
pt.start()
lt.append(pt)
for t in lt:
t.join()
print("We earned a lot of money! Sum=", casino.euro)
Я думаю, вы можете упустить что-то фундаментальное в том, как работают блокировки.Блокировка не имеет представления о том, что она блокирует, и не препятствует ничему, кроме двух потоков, одновременно удерживающих одну и ту же блокировку.Вы хотите убедиться, что ни один поток не может прочитать euro
между другими потоками, которые читают euro
, увеличивают значение чтения и записывают обратно в него.Способ сделать это - обеспечить, чтобы каждый поток, который каким-либо образом мог взаимодействовать с euro
, содержал одну конкретную блокировку.
Когда мы говорим, что какая-то конкретная блокировка защищает определенный фрагмент данных, то, что мыЭто означает, что ни один поток не пытается получить доступ или изменить этот конкретный фрагмент данных без удержания этой конкретной блокировки.Очевидно, для этого требуется, чтобы код был тщательно сконструирован для соответствия этому требованию.