互斥锁
一、 代码展示
① 没加锁(X)
import threading
num = 0
def write1():
global num
i = 1
while i <= 1000000:
num += 1
i += 1
print("result1:%d" % num)
def write2():
global num
i = 1
while i <= 1000000:
# 由于 num 是全局变量,但num += 1 是分三步执行的(详情看总结)
# 若没有加锁,就会出现抢夺资源( num +=1 还没执行完,另一个线程拿这个变量去使用),就会导致 num 的最终值出现错误
num += 1
i += 1
print("result2:%d" % num)
def main():
# 创建两个线程
p1 = threading.Thread(target=write1)
p2 = threading.Thread(target=write2)
# 开启线程
p1.start()
p2.start()
if __name__ == "__main__":
main()
运行结果
result1:1180321
result2:1567595
以上 result2 结果不是一个定值,各种值情况都会出现
② 加了锁(√)
import threading
num = 0
def write1(lock):
global num
i = 1
while i <= 1000000:
# 此处加了锁
lock.acquire()
num += 1
lock.release()
i += 1
print("result1:%d" % num)
def write2(lock):
global num
i = 1
while i <= 1000000:
# 此处加了锁,跑得快的线程会先上锁,使得另一个线程遇到锁时会堵塞,即原地等待。
lock.acquire()
# 由于 num 是全局变量,但num += 1 是分三步执行的
num += 1
# 运行到此处将进行解锁,解除另一个线程的堵塞状态。随后另一个线程上锁,
# 该线程则堵塞,保证了不会出现资源竞争的情况
lock.release()
i += 1
print("result2:%d" % num)
def main():
# 创建一个锁
lock = threading.Lock()
# 创建两个线程
p1 = threading.Thread(target=write1, args=(lock,))
p2 = threading.Thread(target=write2, args=(lock,))
# 开启线程
p1.start()
p2.start()
if __name__ == "__main__":
main()
运行结果
result1:1996142
result2:2000000 # 因为每个线程都会1000000次+1,所以哪个线程最后一次+1输出结果肯定是2000000
二、 总结
-
① 线程之间是共用全局变量的,因为线程是一个进程里分出来的几个任务,使用的是用同一份代码,同样的变量与资源。
-
② 互斥锁一般用在线程需要 共享全局变量 的时候
-
③ 进程与线程之间的关系与区别:
- ① 进程 包含 多个线程
- ② 进程间 不共用 变量与资源;线程间 共用 变量与资源
-
④ num += 1 分三步执行:
-
- cpu从内存中读取num的值(例如 num = 0)
- cpu把读取到的num值加1(num + 1 = 1)
- cpu把计算完的值重新赋值给内存(num = 1)
-