◎知识点
多进程同步之RLock
多线程同步之RLock
◎脚本练习
▽ 多进程同步之RLock
""" RLock也遵守了上下文管理协议,所以可以使用with语句对代码进行简化。 """ ''' from threading import Thread, RLock numa = 0 numb = 0 rlock = RLock() def do_sth(): """ rlock.acquire() try: adda() addb() finally: rlock.release() """ with rlock: adda() addb() def adda(): global numa """ rlock.acquire() try: numa += 1 finally: rlock.release() """ with rlock: numa += 1 def addb(): global numb """ rlock.acquire() try: numb += 1 finally: rlock.release() """ with rlock: numb += 1 if __name__ == '__main__': tlist = [] for i in range(10): t = Thread(target=do_sth) tlist.append(t) t.start() for item in tlist: item.join() print(numa) print(numb) ''' """二、多进程同步之RLock""" """ RLock也遵守了上下文管理协议,所以可以使用with语句对代码进行简化。 """ from multiprocessing import Process, Value, RLock def do_sth(numa, numb, rlock): """ rlock.acquire() try: adda(numa) addb(numb) finally: rlock.release() """ with rlock: adda(numa) addb(numb) def adda(numa): """ rlock.acquire() try: numa += 1 finally: rlock.release() """ with rlock: numa.value += 1 def addb(numb): """ rlock.acquire() try: numb += 1 finally: rlock.release() """ with rlock: numb.value += 1 if __name__ == '__main__': numa = Value('i', 0) numb = Value('i', 0) rlock = RLock() plist = [] for i in range(10): p = Process(target=do_sth, args = (numa, numb, rlock)) plist.append(p) p.start() for item in plist: item.join() print(numa.value) print(numb.value)
▽ 多线程同步之RLock
""" 在同一线程中,当调用了Lock的方法acquire()之后,如果在调用方法release()之前再次调用了 方法acquire(),也会导致死锁。 """ """ from threading import Lock lock = Lock() lock.acquire() print('获得锁') lock.acquire() print('获得锁') lock.release() print('释放锁') lock.release() print('释放锁') """ """ 标准库模块threading中还提供了一个用于表示锁的类对象RLock(Reentrant Lock,可重入锁)。 与Lock相同的是:RLock也提供了用于获得锁的方法acquire()和用于释放锁的方法release()。 与Lock不同的是:在同一个线程中,当调用了RLock的方法acquire()之后,可以在调用方法release()之前 多次调用方法acquire()而不会导致死锁。 """ from threading import RLock rlock = RLock() rlock.acquire() print('获得锁') rlock.acquire() print('获得锁') rlock.release() print('释放锁') rlock.release() print('释放锁') """ 在RLock的内部维护了一个Lock和一个计数器counter。counter记录了锁被acquire的次数。 当线程第一次调用方法acquire()获得锁时,锁的拥有者被保存,同时计数器counter被初始化为1; 当再次调用方法acquire()时,首先判断调用者是否是锁的拥有者,如果是,计数器counter加1。 方法acquire()的定义如下: def acquire(self, blocking=True, timeout=-1): me = get_ident() if self._owner == me: self._count += 1 return 1 rc = self._block.acquire(blocking, timeout) if rc: self._owner = me self._count = 1 return rc 当调用方法release()时,首先判断调用者是否是锁的拥有者,如果是,计数器counter减1; 如果计数器counter减1后变为0,则将锁的拥有者设置为None,然后释放锁。 方法release()的定义如下: def release(self): if self._owner != get_ident(): raise RuntimeError("cannot release un-acquired lock") self._count = count = self._count - 1 if not count: self._owner = None self._block.release() RLock相当于一个门可以上多把锁,上多少锁就得开多少把锁。 因此,方法acquire()和release()必须成对出现。如果在某个线程中调用了n次acquire(),必须 调用n次release()才能释放该线程所占用的锁。
◎脚本地址:https://github.com/anzhihe/learning/blob/master/python/practise/learn-python/python_senior/rlock.py