04-多线程共享全局变量的问题

问题

我们运行下面这段代码

 1 import threading
 2 
 3 
 4 num1 = 0
 5 
 6 def test01(num):
 7     for i in range(num):
 8         global num1
 9         num1 += 1
10     print("test01---------->" + str(num1))
11 
12 
13 def test02(num):
14     for i in range(num):
15         global num1
16         num1 += 1
17     print("test02---------->" + str(num1))
18 
19 
20 def main():
21     t1 = threading.Thread(target = test01, args = (100000, ))   # 创建一个对象
22     t2 = threading.Thread(target = test01, args = (100000, ))   # 创建一个对象
23 
24     # 创建子线程
25     t1.start()
26     t2.start()
27     print(num1)
28 
29 if __name__ == "__main__":
30     main()
View Code

运行结果如下图所示:

 

原因 

我们发现多次运行结果并不相同,下面就解释一下原因

CPU在执行代码的时候是一句一句执行的,我们创建了两个子线程;

这两个线程互相切换,一会儿执行线程t1,一会儿执行线程t2。CPU在执行这些线程中的代码的时候也是一句一句进行执行的。

假如代码在执行线程t1的时候,执行完了global num1和num1 + 1但是没有执行赋值语句,紧接着就去执行线程t2,线程t2在执行的时候也是执行了和线程t1一样的这两句代码,然后CPU在执行线程t1的赋值语句,此时num1的值为1。CPU执行完t1中的赋值语句之后在去执行t2中的赋值语句,执行完t2的赋值语句之后num1的值仍然是1。

解决办法

咱们可以使用上锁的方式来解决这个问题,即线程A在执行的时候不让线程2执行,等到线程1执行完成,再让线程2执行。

具体实现代码如下:

 1 import time
 2 import threading
 3 
 4 
 5 num1 = 0
 6 
 7 def test01(num):
 8     for i in range(num):
 9         mutex.acquire() # 上锁
10         global num1
11         num1 += 1
12         mutex.release()    # 解锁
13     print("test01---------->" + str(num1))
14 
15 
16 def test02(num):
17     for i in range(num):
18         mutex.acquire() # 上锁
19         global num1
20         num1 += 1
21         mutex.release()    # 解锁
22     print("test02---------->" + str(num1))
23 
24 
25 mutex = threading.Lock()
26 
27 
28 def main():
29     t1 = threading.Thread(target = test01, args = (100000, ))   # 创建一个对象
30     t2 = threading.Thread(target = test01, args = (100000, ))   # 创建一个对象
31 
32     # 创建子线程
33     t1.start()
34     t2.start()
35     time.sleep(0.1)
36     print(num1)
37 
38 if __name__ == "__main__":
39     main()
View Code