同步机制在多线程编程中扮演着关键角色,它确保了当多个线程同时访问共享资源时,能够按照预定的顺序和规则执行操作,从而避免竞态条件(race conditions)、死锁(deadlocks)和其他并发问题。在Python中,常见的同步机制包括:
-
锁(Lock)
threading.Lock
是基础的互斥锁,同一时刻只允许一个线程获取锁并执行临界区代码。其他试图获取锁的线程将被阻塞,直到拥有锁的线程释放锁。import threading lock = threading.Lock() def worker(): with lock: # 这里是受保护的临界区代码 shared_resource.operation() thread1 = threading.Thread(target=worker) thread2 = threading.Thread(target=worker) thread1.start() thread2.start()
-
可重入锁(RLock)
threading.RLock
是一种可重入锁,允许同一个线程多次获得同一个锁而不会阻塞自己。这在递归调用或函数内部需要再次加锁的情况下很有用。
-
信号量(Semaphore)
threading.Semaphore
用于控制可以同时访问特定资源的线程数量。初始化时设置一个计数器,每次acquire()减少计数,release()增加计数。当计数为0时,acquire()会阻塞等待。
-
条件变量(Condition)
threading.Condition
提供了更复杂的同步原语,基于条件变量实现线程间的通信和同步。它可以关联到一个锁,并且有wait(), notify(), 和notify_all()方法来协调线程执行。condition = threading.Condition() def consumer(condition): with condition: while not enough_data(): condition.wait() consume_data() def producer(condition): while True: produce_data() with condition: if enough_data(): condition.notify()
-
事件(Event)
threading.Event
对象用于通知线程某些条件已变为真或者某个事件已经发生。线程可以调用event对象的wait()方法阻塞自己,直到其他线程调用event对象的set()方法将其置位。
-
队列(Queue)
- 虽然不是直接的同步原语,但
queue.Queue
等线程安全的数据结构实现了隐式的同步,通过内置的锁和条件变量来保证多线程环境下数据的安全存取。
- 虽然不是直接的同步原语,但
示例:使用Condition进行线程同步
import threading
class SharedResource:
def __init__(self):
self.condition = threading.Condition()
self.data_ready = False
def set_data(self, data):
with self.condition:
self.data = data
self.data_ready = True
self.condition.notify_all()
def get_data(self):
with self.condition:
while not self.data_ready:
self.condition.wait()
return self.data.copy() # 返回一份副本以防止后续修改影响其他线程
resource = SharedResource()
def producer():
resource.set_data(generate_data())
def consumer():
data = resource.get_data()
process_data(data)
producer_thread = threading.Thread(target=producer)
consumer_thread = threading.Thread(target=consumer)
producer_thread.start()
consumer_thread.start()
producer_thread.join()
consumer_thread.join()
在上述例子中,生产者线程会在准备好数据后通过Condition通知消费者线程,消费者线程则会等待这个通知后再去获取数据,这样就实现了对共享资源的同步访问。