demo
import threading
import time
g_num = 0
def fun_add_01(num):
global g_num
for i in range(num):
g_num += 1
print(g_num)
def fun_add_02(num):
global g_num
for i in range(num):
g_num += 1
print(g_num)
def main():
func_01 = threading.Thread(target=fun_add_01,args=(1000000,))
func_02 = threading.Thread(target=fun_add_02, args=(1000000,))
func_01.start()
func_02.start()
time.sleep(5)
print(g_num)
if __name__ == '__main__':
main()
输出结果
1130716
1262620
1262620
解析:
上述问题的产生主要是由两个函数中g_num += 1产生,g_num += 1在执行可以分为三步,
第一步:获取g_num的值
第二步: 让g_num加1
第三步:存储g_num的值
在多线程中,由于线程之间的来回切换,第一个函数中执行完第二步,还没存储到g_num中,线程切换到第二个函数中,此时函数1完成了加1的动作,但g_num传到第二个函数中的值却是没有发生变化的,此时在函数2中继续进行上述操作,当函数2可能完成加1的动作后再次切换到函数1,此时函数1的+1值才会计入到g_num中。由于两个函数不断切换导致许多+1的动作完成后,其值并未计入到内存中,最后导致结果出错
解决方法:
使用互斥锁,互斥锁里面的代码在执行的时候,进程不会切换
互斥锁使用
mutex = threading.Lock()
mutex.acquire()
# 执行代码
mutex.release()
死锁的产生
mutex1 = threading.Lock()
mutex2 = threading.Lock()
线程1
mutex1.acquire()
mutex2.acquire()
# 执行代码
mutex2.release()
mutex1.release()
线程2
mutex2.acquire()
mutex1.acquire()
# 执行代码
mutex1.release()
mutex2.release()
此时,锁1等待锁2解开,锁2等待锁1解开,最终造成了堵塞
避免死锁的方法
1 设置超时时间
2 银行家算法