20、多任务-线程-同步概念、互斥锁解决资源竞争问题

上篇文章中子线程之间出现资源竞争的原因是CPU占用问题,一个子线程的代码没执行完就被切换掉,解决此问题的方法是,让代码全部执行完再切换,或者根本不让执行,不能执行到一半切换另一个线程。原则同银行转账,转账时借钱人把钱转出去,但是收款人没收到,杜绝这种情况。

同步:协同一起去做事情,有步骤,约定好过程,“你先说完,我再说”

如何实现同步?

互斥锁:用threading里的Lock创建,即:

#创建锁,默认是没上锁的
mutex = threading.Lock()

#锁定
mutex.acquire()

#解锁
mutex.release()

上锁后,其它子线程只能堵塞,解锁后解阻塞

说明:
互斥锁也是一个变量,放在函数外面,就是一个全局变量,哪个子线程想用,就可以放到代码里直接中,只是用而不是修改全局变量,不用加global声明

思路:
给两个子线程都上锁,让两个线程去抢,谁先抢到谁先上锁,不只是给第一个子线程上锁
把有资源竞争的地方,都用锁套起来,即:
mutex.acquire()
for i in range(num):
g_num += 1
mutex.release()

注意:
创建锁时,Lock只有首字母是大写,其它是小写,否则运行程序时会报错:threading没有LOCK属性
查看模块中的属性:进入ipython3交互模式,import导入模块,dir(模块名称),例如:进入ipython3后,import
threading dir(threading),即可看到弹出一个列表,里面是属性

1 import threading
  2 import time
  3 
  4 #定义一个全局变量
  5 g_num = 0
  6 
  7 def test1(num):
  8     global g_num
  9     #上锁,如果之前没有被上锁,那么上锁成功
 10     #如果之前已经被上锁,那么此时会堵塞在这里,知道锁被解开
 11     mutex.acquire()
 12     for i in range(num):
 13         g_num += 1
 14     # 解锁
 15     mutex.release()
 16     print("--test1--%s" % g_num)
 17 
 18 
 19 def test2(num):
 20     global g_num
 21     mutex.acquire()
 22     for i in range(num):
 23         g_num += 1
 24     mutex.release()
 25     print("--test1--%s" % g_num)
 26     print("--test2--%s" % g_num)
 27 
 28 
 29 #创建互斥锁,默认没有上锁
 30 mutex = threading.Lock()
 31 
 32 
 33 def main():
 34 
 35     t1 = threading.Thread(target=test1,args=(1000000,))
 36     t2 = threading.Thread(target=test2,args=(1000000,))
 37 
 38     t1.start()
 39     t2.start()
 40 
 41     time.sleep(5)
 42 
 43     print("--main--%s" % g_num)
 44 if __name__ == "__main__":
 45     main()


以上代码是对for循环部分进行上锁,意味着当所有的for完成后才会解锁,当循环时间足够长的时候,另一个线程就要等很长时间。

上锁的原则,上的代码越少越好。
修改代码,只把原来出问题的那一句代码上锁,即:
把上锁解锁放到for循环里,只对+1进行上锁
for i in range(num):
mutex.acquire()
g_num += 1
# 解锁
mutex.release()

1 import threading
  2 import time
  3 
  4 #定义一个全局变量
  5 g_num = 0
  6 
  7 def test1(num):
  8     global g_num
  9     #上锁,如果之前没有被上锁,那么上锁成功
 10     #如果之前已经被上锁,那么此时会堵塞在这里,知道锁被解开
 11     for i in range(num):
 12         mutex.acquire()
 13         g_num += 1
 14         # 解锁
 15         mutex.release()
 16     print("--test1--%s" % g_num)
 17 
 18 
 19 def test2(num):
 20     global g_num
 21     for i in range(num):
 22         mutex.acquire()
 23         g_num += 1
 24         # 解锁
 25         mutex.release()
 26     print("--test2--%s" % g_num)
 27 
 28 
 29 #创建互斥锁,默认没有上锁
 30 mutex = threading.Lock()
 31 
 32 
 33 def main():

修改代码后运行的结果如下:
–test1–1968722
–test2–2000000
–main–2000000

虽然test1是加完了100000次之后才进行的打印,但是在1000000执行过程中,test2也在对全局变量做更改,导致test1执行完指定次数后,输入的结果大于100000,但主线程打印出来的全局变量的最终结果是200000

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值