背景
当属于并发线程的两个或过个操作尝试访问共享内存,并且至少有一个操作能够修改数据的状态时,这时如果没有恰当的同步机制,就会导致竞态条件。
解决竞态条件最简单的方式是使用锁。
当一个线程想要访问共享内存的某一部分区域时,他必须要使用前获取到该部分的锁。在完成操作后,线程必须要释放掉之前获取的锁。对于线程来说,它对锁的需求要求在某个给定的时刻,只有一个线程能够使用共享内存的部分。
虽然简单,但在实际情况下,这种方式常常会导致死锁的发生。
Python 中可以用以实现线程同步的方式共有 5 种:
Lock()
这是最普通的锁,拥有两种状态:上锁和未上锁。
缺点:是最低级的同步基础组件。从实践角度,会导致严重的死锁。因此,还需要使用其他方法来确保对共享内存的同步访问避免竞态条件。
RLock()
这是对 Lock() 的升级,在类外面能实现线程安全的访问,同时又使用类里面相同的方法。它避免了不同线程在对同一资源要求上锁时,产生的死锁。但要求上锁和解锁成对出现。
Semaphore()
semaphore 的基本实现是基于锁,它在锁的基础上增加了计数器的设置。
缺点:等待与信号操作要在原子块中执行。
Condition()
condition 基本实现也是基于锁,标识了一个线程等待特定的条件,另一个线程通知它条件已经发生。在接口上,除了上锁(acquire)和解锁(release),还增加了等待(wait)和通知(notify)。
Event()
event 和 semaphore 类似,它通过 bool 类型来区别信号,它另外还增加了等待接口。