锁定不会像我希望的那样锁定我的变量

2024-10-06 06:56:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试使用多线程增加一个变量。但是,当我运行代码时,计数器保持在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“


Tags: theltselfptlockdefthreadtmp
3条回答

试试这个

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

你有两个虫子。第一个是所罗门·斯洛在回答中提到的。在整个读-修改-写操作期间,您不会持有锁。正如您所建议的,可以通过向上移动锁来解决此问题

但是您还有一个问题,没有锁保护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交互的每个线程都持有一个特定的锁

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

您的线程在锁定变量之前都读取

    tmp = self.the_casino.euro

第二次睡眠确保所有线程在更改self.the_casino.euro之前都有时间看到self.the_casino.euro等于零

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


如果要获取5,则需要将读取和更新变量设置为单个原子操作。您可以通过将读取和更新放在同一个关键部分来实现这一点

相关问题 更多 >