锁定并不能锁定我想要的变量

时间:2019-03-24 16:01:37

标签: python multithreading locking

我正在尝试使用多线程来增加变量。但是,当我运行代码时,计数器保持在1。当我删除第二个睡眠时,它会正常工作(增加到5),但是我似乎无法弄清楚如何正确锁定变量。

在创建tmp之前,我已经尝试过锁定变量以及其他锁定方法(使用lock,try-finalize等)。

class Casino:
    euro = 0


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)
        tmp = self.the_casino.euro
        time.sleep(1)
        self.lock.acquire()
        self.the_casino.euro = tmp + 1
        self.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)

预期输出为“我们赚了……总和= 5”,但它是“ ...总和= 1”

3 个答案:

答案 0 :(得分:0)

您的线程在锁定变量之前所有 read 变量

    tmp = self.the_casino.euro

第二次睡眠可确保所有线程有时间在它们中的任何一个更改之前看到self.the_casino.euro等于零。

然后,他们醒来后,将每个人都将其设置为tmp + 1(即,将他们每个人都将其设置为1)。


如果要获取5,则需要使读取和更新变量成为单个原子操作。您可以通过将读取的内容和更新的内容放在同一关键部分来实现此目的。

答案 1 :(得分:0)

尝试一下

class Casino:
euro = 0


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):
        try:
            self.lock.acquire()
            self.the_casino.euro += 1
        finally:
            self.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)

问题是您实际上并没有增加Casino.euro,它始终为0并分配给tmp。

答案 2 :(得分:0)

您有两个错误。第一个是所罗门·斯洛的答案中提到的那个。在整个读取-修改-写入操作期间,您无需保持锁定状态。如您建议的那样,可以通过向上移动锁定获取来解决该问题。

但是您还有另一个问题-没有锁保护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进行交互的线程都拥有一个特定的锁。

当我们说某个特定的锁保护了某个特定的数据段时,我们的意思是没有线程在不持有该特定锁的情况下尝试访问或修改该特定的数据段。显然,这需要仔细构造代码以符合此要求。