多线程/多进程同步之RLock(递归锁\可重入锁)

用途:解决死锁问题;只要RLock的内部计数器大于1,则其它线程将不能获得锁。

#【1】多线程同步之RLock

  1 """
  2 在同一线程中,当调用了Lock的方法acquire()之后,如果在调用方法release()之前
  3 再次调用了方法acquire(),也会导致死锁。
  4 """
  5 from threading import Lock
  6 
  7 lock = Lock()
  8 
  9 lock.acquire()
 10 print('获得锁')
 11 
 12 lock.acquire()
 13 print('获得锁')
 14 
 15 lock.release()
 16 print('释放锁')
 17 
 18 lock.release()
 19 print('释放锁')
 20 
 21 
 22 """
 23 标准库模块threading中还提供了一个用于表示锁的类对象RLock(Reentrant Lock,可重入锁)。
 24 与Lock相同的是:RLock也提供了用于获得锁的方法acquire()和用于释放锁的方法release()。
 25 与Lock不同的是:在同一个线程中,当调用了RLock的方法acquire()之后,可以在调用方法release()之前
 26 多次调用方法acquire()而不会导致死锁。
 27 """
 28 from threading import RLock
 29 
 30 rlock = RLock()
 31 
 32 rlock.acquire()
 33 print('获得锁')
 34 
 35 rlock.acquire()
 36 print('获得锁')
 37 
 38 rlock.acquire()
 39 print('获得锁')
 40 
 41 rlock.release()
 42 print('释放锁')
 43 
 44 rlock.release()
 45 print('释放锁')
 46 
 47 rlock.release()
 48 print('释放锁')
 49 
 50 """
 51 在RLock的内部维护了一个Lock和一个计数器counter。counter记录了锁被acquire()的次数。
 52 当线程第一次调用方法acquire()获得锁时,锁的拥有者被保存,同时计数器counter被初始化为1;
 53 当再次调用方法acquire()时,首先判断调用者是否是锁的拥有者,如果是,计数器counter加1。
 54 """
 55 #方法acquire()的定义如下:
 56 def acquire(self, blocking=True, timeout=-1):
 57     me = get_ident()
 58     if self._owner == me:
 59         self._count += 1
 60         return 1
 61     rc = self._block.acquire(blocking, timeout)
 62     if rc:
 63         self._owner = me
 64         self._count = 1
 65     return rc
 66     
 67     
 68 """
 69 当调用方法release()时,首先判断调用者是否是锁的拥有者,如果是,计数器counter减1;
 70 如果counter减1后变为0,则将锁的拥有者设置为None,然后释放锁。
 71 
 72 RLock相当于一个门可以上多把锁,上多少锁就得开多少把锁。
 73 因此,方法acquire()和release()必须成对出现。如果在某个线程中调用了n次acquire(),必须成对出现。
 74 如果在某个线程中调用了n次acquire(),必须调用n次release()才能释放该线程所占用的锁。
 75 """
 76 方法release()的定义如下:
 77     def release(self):
 78         if self._owner != get_ident():
 79             raise RuntimeError("cannot release un-acquired lock")
 80         self._count = count = self._count - 1
 81         if not count:
 82             self._owner = None
 83             self._block.release()
 84 
 85             
 86 """
 87 RLock也遵守了上下文管理协议,所以可以使用with语句对代码进行简化。
 88 """            
 89 
 90 from threading import Thread, RLock
 91 
 92 numa = 0
 93 numb = 0
 94 
 95 rlock = RLock()
 96 
 97 def do_sth():
 98     """功能等同于下面with语句。
 99     rlock.acquire()
100     try:
101         adda()
102         addb()
103     finally:
104         rlock.release()
105     """
106     with rlock:
107         adda()
108         addb()
109 
110 def adda():
111     global numa
112     """功能等同于下面with语句。
113     rlock.acquire()
114     try:
115         numa += 1
116     finally:
117         rlock.release()
118     """
119     with rlock:
120         numa += 1
121 
122 def addb():
123     global numb
124     """功能等同于下面with语句。
125     rlock.acquire()
126     try:
127         numb += 1
128     finally:
129         rlock.release()
130     """
131     with rlock:
132         numb += 1
133 
134 tlist = []
135 
136 for i in range(10):创建10个线程
137     t = Thread(target=do_sth)
138     tlist.append(t)
139     t.start()
140 
141 for item in tlist:   #阻塞父线程
142     item.join()
143 
144 print(numa)
145 print(numb)
View Code

#【2】多进程同步之RLock

 1 #RLock也遵守了上下文管理协议,所以可以使用with语句对代码进行简化。
 2 from multiprocessing import Process, Value, RLock
 3 
 4 numa = Value('i', 1)
 5 numb = Value('i', 1)
 6 rlock = RLock()
 7 
 8 
 9 def do_sth(numa, numb):
10     rlock.acquire()
11     try:
12         adda(numa)
13         addb(numb)
14     finally:
15         rlock.release()
16 
17 
18 def adda(num):
19     global numa
20     rlock.acquire()
21     try:
22         num.value += 1
23     finally:
24         rlock.release()
25 
26 
27 def addb(num):
28     global numb
29     rlock.acquire()
30     try:
31         num.value += 1
32     finally:
33         rlock.release()
34 
35 
36 if __name__ == "__main__":
37     plist = []
38 
39     for i in range(10):
40         p = Process(target=do_sth, args=(numa, numb))
41         plist.append(p)
42         p.start()
43 
44     for item in plist:
45         item.join()
46 
47     print(numa.value)
48     print(numb.value)
View Code

 

posted @ 2019-06-28 23:49  山的那一边  阅读(299)  评论(0)    收藏  举报