MST

星途 面试题库

面试题:Python多线程资源竞争下如何正确使用锁机制

在Python多线程中,为解决资源竞争常使用锁机制。请详细阐述如何正确地在代码中使用`threading.Lock`来避免资源竞争,并且说明死锁产生的原因以及如何预防死锁。
14.2万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

使用threading.Lock避免资源竞争

  1. 创建锁对象:在需要保护共享资源的代码部分,首先要创建一个Lock对象。例如:
import threading

lock = threading.Lock()
  1. 使用锁来保护共享资源:在访问共享资源之前,调用acquire()方法获取锁,访问完成后,调用release()方法释放锁。
shared_resource = 0

def increment():
    global shared_resource
    lock.acquire()
    try:
        shared_resource += 1
    finally:
        lock.release()
  1. 使用with语句(推荐):可以使用with语句来自动管理锁的获取和释放,这样代码更简洁,且能确保锁一定会被释放,即使在代码块中发生异常。
def increment():
    global shared_resource
    with lock:
        shared_resource += 1

死锁产生的原因

  1. 相互等待:当两个或多个线程互相持有对方需要的锁,并且都在等待对方释放锁时,就会发生死锁。例如,线程A持有锁1并等待锁2,而线程B持有锁2并等待锁1。
  2. 资源分配不当:如果线程获取锁的顺序不一致,也容易导致死锁。比如在一个复杂的系统中,不同线程获取锁的顺序没有统一规划。

预防死锁

  1. 统一加锁顺序:所有线程按照相同的顺序获取锁。例如,如果有锁A和锁B,所有线程都先获取锁A,再获取锁B。这样可以避免循环等待的情况。
  2. 使用超时机制:在获取锁时设置超时时间,如果在规定时间内没有获取到锁,就放弃获取并进行相应处理(例如,释放已经获取的锁,等待一段时间后重试)。threading.Lock本身没有直接支持超时,但threading.RLock(可重入锁)的acquire方法有timeout参数。可以使用try - except语句来处理获取锁超时的情况。
lock = threading.RLock()
if lock.acquire(timeout=1):  # 尝试获取锁,超时时间1秒
    try:
        # 访问共享资源
        pass
    finally:
        lock.release()
else:
    # 处理获取锁失败的情况
    pass
  1. 死锁检测:使用工具如DeadlockDetector(可通过第三方库实现)来检测程序运行时是否发生死锁。这种方法是事后检测,发现死锁后可以分析原因并修改代码避免再次发生。