0

我得到了一个简单的 python 程序来分析。它工作正常,并且随机输出 13、14 和 15(当然)。我可以看到为什么要打印 13 和 14,但我不明白 15 是从哪里来的。

请解释。

from threading import Thread
import random
import time
import sys

def rwait():
    amt = random.uniform(0.01,0.1)
    time.sleep(amt)

x = 0

key = True

def lockx():
    global key
    while not key:
        time.sleep(0)
    rwait()
    key = False

def unlockx():
    global key
    key = True

def A():
    global x
    rwait()
    lockx()
    reg = x
    reg = reg+1
    rwait()
    x = reg
    unlockx()

def B():
    global x
    rwait()
    lockx()
    reg = x
    reg = reg+2
    rwait()
    x = reg
    unlockx()

def main():
    global x
    x = 12
    p1 = Thread(target=B)
    p1.start()
    A()
    p1.join()
    print("x=",x)


for k in range(20):
    main()
4

3 回答 3

2

您的函数名称似乎暗示它们正在执行锁定,但事实并非如此。这有两个原因:

  • 访问key不能保证原子性。
  • 即使它们是,在key读取的时间和它的值之间存在竞争True,以及它被使用和设置为的时间False

结果,您的两个线程最终以不同步的方式修改共享(在本例中为全局)状态。因此,三种情况中的任何一种都是可能的:

  1. x仅递增 1 -在被读取之后但在递增的值被存储回之前B完全执行。xA
  2. x仅增加 2 - 与上述相同的情况AB反转。
  3. x递增 3 -A或分别在或B之前完全执行。BA

要正确同步两个线程,您必须使用锁定。这是使用 Threading 提供的工具对您的代码进行的改编:

from threading import Thread, Lock

x = 0

lock = Lock()

def lockx():
    global lock
    lock.acquire()

def unlockx():
    global lock
    lock.release()

def A():
    global x
    lockx()
    reg = x
    reg = reg+1
    x = reg
    unlockx()

def B():
    global x
    lockx()
    reg = x
    reg = reg+2
    x = reg
    unlockx()

def main():
    global x
    x = 12
    p1 = Thread(target=B)
    p1.start()
    A()
    p1.join()
    print("x=",x)

for k in range(20):
    main()
于 2013-11-01T12:02:43.977 回答
2

可能会发生三种不同的情况:

  • 线程 A 和 B在更改x 之前读取,然后

    • 线程 A 写入其结果 (13),并且

    • 线程 B 写入其结果 (14),

    第二个写线程获胜。

  • 线程 A 或 Bx先读取,然后在另一个线程读取之前写入。结果:15,A 读取 12,加 1 并写入 13,然后 B 读取 13 并写入 15,反之亦然。

于 2013-11-01T12:00:31.530 回答
0

您在这里演示了一个经典的并发问题。两个写入器同时操作,因此可能会覆盖另一个写入的数据。

如果您收到 13,则线程在线程写入其结果之前A读取并在写入其结果之后写入。BA B

如果您收到 14,则线程在线程写入其结果之前B读取并在写入其结果之后写入。AB A

如果您收到 15,则一个线程在另一个线程写入其结果之后读取(并计算和写入)。然后无法确定两个线程的顺序。

然而,更有趣的问题是,为什么锁定机制 ( lockx/ unlockx) 显然不起作用。它会起作用吗,结果你总是会得到15。

于 2013-11-01T12:00:35.137 回答