MST

星途 面试题库

面试题:Python多线程死锁避免之锁的合理使用

在一个Python多线程程序中,有多个线程需要访问和修改共享资源,为了避免死锁,你会如何设计锁的获取和释放机制?请详细阐述并给出代码示例。
12.5万 热度难度
编程语言Python

知识考点

AI 面试

面试题答案

一键面试

避免死锁的锁获取和释放机制设计

  1. 按顺序获取锁:所有线程都按照相同的顺序获取锁,这样可以避免循环等待导致的死锁。例如,假设有两个锁 lock1lock2,所有线程都先获取 lock1,再获取 lock2
  2. 使用 try - finally:在获取锁之后,无论是否发生异常,都要确保锁能正确释放。try - finally 块可以保证在 try 块中的代码执行完毕后(无论是否发生异常),都会执行 finally 块中的代码,从而释放锁。
  3. 设置锁的超时时间:在获取锁时设置一个超时时间,如果在超时时间内没有获取到锁,则放弃获取并进行相应处理,避免线程无限期等待。

代码示例

import threading
import time


# 创建两个锁
lock1 = threading.Lock()
lock2 = threading.Lock()


def thread_function():
    # 按顺序获取锁
    if lock1.acquire(timeout=1):
        try:
            print(f"{threading.current_thread().name} 获取了 lock1")
            time.sleep(0.1)
            if lock2.acquire(timeout=1):
                try:
                    print(f"{threading.current_thread().name} 获取了 lock2")
                    # 这里访问和修改共享资源
                    time.sleep(0.1)
                finally:
                    lock2.release()
                    print(f"{threading.current_thread().name} 释放了 lock2")
        finally:
            lock1.release()
            print(f"{threading.current_thread().name} 释放了 lock1")


# 创建并启动多个线程
threads = []
for i in range(3):
    t = threading.Thread(target=thread_function)
    threads.append(t)
    t.start()

# 等待所有线程完成
for t in threads:
    t.join()

在上述代码中:

  • 每个线程都尝试先获取 lock1,设置超时时间为1秒,如果获取成功,在 try 块中执行相关操作,最后在 finally 块中释放 lock1
  • 在获取 lock1 成功后,再尝试获取 lock2,同样设置超时时间为1秒,获取成功后执行操作并在 finally 块中释放 lock2
  • 通过这种方式,既保证了按顺序获取锁,又使用了超时机制和 try - finally 块确保锁的正确获取和释放,从而避免死锁。