Rlock
我们前面说过了Lock,python的threading库中还提供了一个可重入锁Rlock。
还记得吗,对于Lock,我们不能说Lock被某个线程持有,或Lock属于某个线程,因为一个线程使用acquire使锁进入locked态,任何线程都可以调用release把锁“打开”——恢复unlocked态。
这里的Rlock相比于Lock,增加了两个特性。
1.Rlock
锁是被某个线程持有的(owned by the thread that locked it)
线程T1调用了acquire
时,只有T1可以调用release使Rlock
回到unlocked状态。可以这么理解Rlock
被T1线程抢回家了,只要T1线程不放人,别的线程想要acquire
的话都会阻塞(同上一篇,这里不讨论 blocking = False
的情况)。
2.Rlock
是可重入的锁,有n层acquire
就必须有n层release才能释放锁。
Condition
Condition
条件变量——锁的一种高级形式。Condition
可以让多个线程被挂起,直到另外的某个线程调用notify
或notify_all
方法发出“放行”信号,之前挂起的若干个或所有线程会被放行。
Condition
实现线程间同步是有锁参与的,默认的内置锁是RLock
。
.wait(timeout=None)
方法
执行.wait()
会自动执行一次内置锁的release()然后挂起,这也提醒了我们执行.wait()
前这个线程必须acquire()
到了内置锁,否则会报RuntimeError
。
要注意:阻塞不会在收到notify()
或notify_all
信号后立刻结束,因为wait()
会尝试重新获取锁,所以必须要等nofity
的线程手动释放锁。
.notify(n=1)
方法
执行.notify()
前这个线程必须acquire()
到了内置锁,否则会报RuntimeError
。
发出放行信号,放行n个等待线程,.notify_all()
则会放行所有等待者。但要注意notify()方法本身不会自动release,还需要手动调用release放弃锁的所有权,才会真正让等待者开始执行。
.wait_for(predicate, timeout=None)
方法
更加实用,比如在一个消费者生产者模型中,消费者遇到库存为0的时候会wait
,生产者补充100单位库存后,发出notify_all
信号,使得所有wait
中的顾客都被激活。
但这些顾客是否一定能买到东西呢?答案是不一定。有可能第一位顾客就是个大款,直接买光了100单位,后面的顾客已经被唤醒,但库存仍然为0,如果此时不增加一个确认机制的话,库存很可能就被买负了。
wait_for
就提供了一个确认机制:当predicate参数为False时,持续wait。
不考虑time out超时自动放行的话,相当于执行了:
While not predicate:
condition.wait()
使得每一次wait
被激活后,往下执行之前还会再确认一次predicate是否为True。有货才购买,无货只能继续等待。