我得到了一个简单的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()
答案 0 :(得分:2)
可能会发生三种不同的事情:
主题A和B在更改之前阅读x
,然后
线程A写出其结果(13)和
线程B写出其结果(14),
和写第二个帖子获胜。
线程A或B首先读取x
,和在另一个线程读取之前写入。结果:15,A读取12,加1,写13,B读13,写15,反之亦然。
答案 1 :(得分:2)
您的函数名称似乎意味着它们正在执行锁定,而它们并非如此。这有两个原因:
key
的访问不保证原子性。key
读取时间及其值为True
之间,以及使用时间和设置为False
之间存在争用。因此,您的两个线程最终以不同步的方式修改共享(在这种情况下为全局)状态。因此,三种情况中的任何一种都是可能的:
x
仅增加1 - B
在x
被A
读取后完全执行但在增加的值被存储回来之前执行。x
仅增加2 - 与A
和B
相反的上述情况相同。x
增加3 - A
或B
分别在B
或A
之前完成。要正确同步两个线程,必须使用锁定。以下是使用线程提供的工具改编您的代码:
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()
答案 2 :(得分:0)
您已在此处演示了经典并发问题。两个写入器同时起作用,因此可能会覆盖另一个写入的数据。
如果您收到13,那么线程A
在线程B
写入其结果之前读取,而A
在之后写入 B
写了结果。
如果收到14,那么线程B
在线程A
写入结果之前读取,而B
在之后写入 A
写了结果。
如果你收到15,那么一个线程在之后读取(并计算并写入),另一个线程已经写出了它的结果。那时无法确定两个线程的顺序。
然而,更有趣的问题是锁定机制(lockx
/ unlockx
)显然不起作用的原因。它会起作用吗,结果总是得到15分。