面试题答案
一键面试使用锁机制解决资源竞争问题
在Python多线程程序中,threading.Lock
是一种常用的锁机制。当一个线程获取到锁时,其他线程必须等待该线程释放锁后才能获取并访问共享资源,从而避免资源竞争。
示例代码如下:
import threading
# 共享资源
shared_variable = 0
lock = threading.Lock()
def increment():
global shared_variable
for _ in range(100000):
# 获取锁
lock.acquire()
try:
shared_variable += 1
finally:
# 释放锁
lock.release()
threads = []
for _ in range(10):
t = threading.Thread(target=increment)
threads.append(t)
t.start()
for t in threads:
t.join()
print(f"Final value of shared variable: {shared_variable}")
在上述代码中,每个线程在修改shared_variable
之前获取锁,修改完成后释放锁,确保同一时间只有一个线程可以修改共享变量。
避免死锁的方法
在复杂场景下,死锁可能会发生,即两个或多个线程相互等待对方释放锁。以下是几种避免死锁的方法:
- 按顺序获取锁:
所有线程按照相同的顺序获取多个锁。例如,如果有锁
lock1
和lock2
,所有线程都先获取lock1
,再获取lock2
。这样可以避免循环等待的情况。
示例代码:
import threading
lock1 = threading.Lock()
lock2 = threading.Lock()
def thread1():
lock1.acquire()
try:
print("Thread 1 acquired lock1")
lock2.acquire()
try:
print("Thread 1 acquired lock2")
finally:
lock2.release()
finally:
lock1.release()
def thread2():
lock1.acquire()
try:
print("Thread 2 acquired lock1")
lock2.acquire()
try:
print("Thread 2 acquired lock2")
finally:
lock2.release()
finally:
lock1.release()
t1 = threading.Thread(target=thread1)
t2 = threading.Thread(target=thread2)
t1.start()
t2.start()
t1.join()
t2.join()
在这个例子中,两个线程都先获取lock1
,再获取lock2
,避免了死锁。
- 使用超时机制: 在获取锁时设置超时时间,如果在规定时间内没有获取到锁,则放弃获取并进行其他处理。
示例代码:
import threading
import time
lock1 = threading.Lock()
lock2 = threading.Lock()
def thread3():
if lock1.acquire(timeout=1):
try:
print("Thread 3 acquired lock1")
if lock2.acquire(timeout=1):
try:
print("Thread 3 acquired lock2")
finally:
lock2.release()
finally:
lock1.release()
else:
print("Thread 3 could not acquire lock1 within 1 second")
def thread4():
if lock2.acquire(timeout=1):
try:
print("Thread 4 acquired lock2")
if lock1.acquire(timeout=1):
try:
print("Thread 4 acquired lock1")
finally:
lock1.release()
finally:
lock2.release()
else:
print("Thread 4 could not acquire lock2 within 1 second")
t3 = threading.Thread(target=thread3)
t4 = threading.Thread(target=thread4)
t3.start()
t4.start()
t3.join()
t4.join()
此代码中,线程在获取锁时设置了1秒的超时时间,如果获取失败会打印提示信息,避免了无限等待导致死锁。
- 资源分配图算法: 在复杂系统中,可以使用资源分配图算法(如银行家算法)来检测和避免死锁。该算法通过跟踪系统中资源的分配情况,在分配资源前进行安全性检查,确保不会导致死锁。不过,这种方法实现起来相对复杂,通常适用于大型多线程系统。