奇怪的python线程输出

时间:2013-11-01 11:44:20

标签: python multithreading python-3.x locking

我得到了一个简单的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()

3 个答案:

答案 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之间存在争用。

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

  1. x仅增加1 - BxA读取后完全执行但在增加的值被存储回来之前执行。
  2. x仅增加2 - 与AB相反的上述情况相同。
  3. x增加3 - AB分别在BA之前完成。
  4. 要正确同步两个线程,必须使用锁定。以下是使用线程提供的工具改编您的代码:

    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分。