多线程/多进程同步之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)
#【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)
------山的那一边

浙公网安备 33010602011771号