使用threading.Lock
避免资源竞争
- 创建锁对象:在需要保护共享资源的代码部分,首先要创建一个
Lock
对象。例如:
import threading
lock = threading.Lock()
- 使用锁来保护共享资源:在访问共享资源之前,调用
acquire()
方法获取锁,访问完成后,调用release()
方法释放锁。
shared_resource = 0
def increment():
global shared_resource
lock.acquire()
try:
shared_resource += 1
finally:
lock.release()
- 使用
with
语句(推荐):可以使用with
语句来自动管理锁的获取和释放,这样代码更简洁,且能确保锁一定会被释放,即使在代码块中发生异常。
def increment():
global shared_resource
with lock:
shared_resource += 1
死锁产生的原因
- 相互等待:当两个或多个线程互相持有对方需要的锁,并且都在等待对方释放锁时,就会发生死锁。例如,线程A持有锁1并等待锁2,而线程B持有锁2并等待锁1。
- 资源分配不当:如果线程获取锁的顺序不一致,也容易导致死锁。比如在一个复杂的系统中,不同线程获取锁的顺序没有统一规划。
预防死锁
- 统一加锁顺序:所有线程按照相同的顺序获取锁。例如,如果有锁A和锁B,所有线程都先获取锁A,再获取锁B。这样可以避免循环等待的情况。
- 使用超时机制:在获取锁时设置超时时间,如果在规定时间内没有获取到锁,就放弃获取并进行相应处理(例如,释放已经获取的锁,等待一段时间后重试)。
threading.Lock
本身没有直接支持超时,但threading.RLock
(可重入锁)的acquire
方法有timeout
参数。可以使用try - except
语句来处理获取锁超时的情况。
lock = threading.RLock()
if lock.acquire(timeout=1): # 尝试获取锁,超时时间1秒
try:
# 访问共享资源
pass
finally:
lock.release()
else:
# 处理获取锁失败的情况
pass
- 死锁检测:使用工具如
DeadlockDetector
(可通过第三方库实现)来检测程序运行时是否发生死锁。这种方法是事后检测,发现死锁后可以分析原因并修改代码避免再次发生。