48_并发编程-线程-资源共享/锁

Posted hq82

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了48_并发编程-线程-资源共享/锁相关的知识,希望对你有一定的参考价值。

一、数据共享
 
  多个线程内部有自己的数据栈,数据不共享;全局变量在多个线程之间是共享的。
技术分享图片
 1 # 线程数据共享不安全加锁
 2 
 3 import time
 4 from threading import Thread, Lock
 5 
 6 
 7 num = 100
 8 
 9 def func(t_lock):
10     global num
11     t_lock.acquire()
12     mid = num
13     mid -= 1
14     time.sleep(0.01) # 设置一个时间,模拟数据修改时,先从内存中拿出作修改,在把结果放回去的时间差
15     num = mid
16     t_lock.release()
17 
18 if __name__ == __main__:
19 
20     t_lock = Lock()
21 
22     t_lst = []
23     for i in range(10):
24         t_thread = Thread(target=func, args=(t_lock,))    
25         t_lst.append(t_thread)
26         t_thread.start()
27     [t_obj.join() for t_obj in t_lst]    #必须加join,因为主线程和子线程不一定谁快,一般都是主线程快一些,所有我们要等子线程执行完毕才能看出效果    
28 
29     print(主线程结束!, num)    # 结果为90
数据共享实例
 
二、同步锁(互斥锁) - 产生死锁
 
  进程也有死锁与递归锁,在进程那里忘记说了,放到这里一切说了额,进程的死锁和线程的是一样的,而且一般情况下进程之间是数据不共享的,不需要加锁,由于线程是对全局的数据共享的,所以对于全局的数据进行操作的时候,要加锁。
  死锁: 是指两个或两个以上的进程或线程在执行过程中,因争夺资源而造成的一种互相等待的现象,若无外力作用,它们都将无法推进下去。此时称系统处于死锁状态或系统产生了死锁,这些永远在互相等待的进程称为死锁进程,如下就是死锁
 
技术分享图片
 1 from threading import Thread,Lock
 2 import time
 3 
 4 class MyThread(Thread):
 5     def run(self):
 6         self.func1()
 7         self.func2()
 8     def func1(self):
 9         mutexA.acquire()
10         print(33[41m%s 拿到A锁>>>33[0m %self.name)
11         mutexB.acquire()
12         print(33[42m%s 拿到B锁>>>33[0m %self.name)
13         mutexB.release()
14         mutexA.release()
15 
16     def func2(self):
17         mutexB.acquire()  
18         print(33[43m%s 拿到B锁???33[0m %self.name)
19         time.sleep(2)
20 #分析:当线程1执行完func1,然后执行到这里的时候,拿到了B锁,线程2执行func1的时候拿到了A锁,那么线程2还要继续执行func1里面的代码,再去拿B锁的时候,发现B锁被人拿了,那么就一直等着别人把B锁释放,那么就一直等着,等到线程1的sleep时间用完之后,线程1继续执行func2,需要拿A锁了,但是A锁被线程2拿着呢,还没有释放,因为他在等着B锁被释放,那么这俩人就尴尬了,你拿着我的老A,我拿着你的B,这就尴尬了,俩人就停在了原地
21         
22         mutexA.acquire()
23         print(33[44m%s 拿到A锁???33[0m %self.name)
24         mutexA.release()
25         mutexB.release()
26 
27 if __name__ == __main__:
28 
29     mutexA=Lock()    # 同步锁必须这样创建
30     mutexB=Lock()
31     for i in range(10):
32         t=MyThread()
33         t.start()
34 
35 ‘‘‘
36 Thread-1 拿到A锁>>>
37 Thread-1 拿到B锁>>>
38 Thread-1 拿到B锁???
39 Thread-2 拿到A锁>>>
40 然后就卡住,死锁了
41 ‘‘‘
死锁现象

技术分享图片

 
三、解决死锁方案 - 递归锁
 
  解决方法,递归锁,在Python中为了支持在同一线程中多次请求同一资源,python提供了可重入锁RLock。
  这个RLock内部维护着一个Lock和一个counter变量,counter记录了acquire的次数,从而使得资源可以被多次require。直到一个线程所有的acquire都被release,其他的线程才能获得资源。上面的例子如果使用RLock代替Lock,则不会发生死锁:
 
技术分享图片
 1 import time
 2 from threading import Thread,RLock
 3 
 4 
 5 class MyThread(Thread):
 6 
 7     def __init__(self, lockA, lockB):
 8         super().__init__()
 9         self.lockA = lockA
10         self.lockB = lockB
11     def run(self):
12         self.func1()
13         self.func2()
14 
15     def func1(self):
16         self.lockA.acquire()
17         print(我是func1)
18         self.lockB.acquire()
19         print(func1中有其他事)
20         self.lockB.release()
21         self.lockA.release()
22 
23     def func2(self):
24         self.lockB.acquire()
25         print(我是func2)
26         time.sleep(0.5)
27         self.lockA.acquire()
28         print(func2中有什么事)
29         self.lockA.release()
30         self.lockB.release()
31 
32 if __name__ == __main__:
33 
34     lockA = lockB = RLock()
35 
36     t1 = MyThread(lockA, lockB)
37     t1.start()
38     t2 = MyThread(lockA, lockB)
39     t2.start()
40     print(嗯嗯,两人不错)
递归锁

技术分享图片

以上是关于48_并发编程-线程-资源共享/锁的主要内容,如果未能解决你的问题,请参考以下文章

python并发编程之线程(创建线程,锁(死锁现象,递归锁),GIL锁)

并发编程2_synchronized锁

并发编程2_synchronized锁

并发编程2_synchronized锁

并发编程2_synchronized锁

并发编程--线程开启线程守护线程线程互斥锁