def f():
lock1.acquire()
task_protected_by_lock1() # Might acquire lock2 internally
lock2.acquire()
task_protected_by_lock1_and_lock2()
lock1.release()
task_protected_by_lock2() # Might acquire lock1 internally
lock2.release()
但是,我发现无法正确处理 SIGINT,因为它会在随机位置引发 KeyBoardInterrupt 异常。我需要保证当控制流退出时,lock1和lock2都被释放
f()
(即正常返回或未处理的异常)。
我知道 SIGINT 可以暂时被屏蔽。然而,正确恢复面具成为另一个挑战,因为它可能已经被外部掩盖了。此外,锁之间执行的任务也可能会调整信号掩码。我相信必须有更好的解决方案。
我想知道是否有一种方法可以让我利用上下文管理器(
with
声明)来实现它。我考虑过以下内容,但没有一个适合我的用例:
with
声明def f():
with lock1, lock2:
task_protected_by_lock1() # Bad: acquiring lock2 internally will cause deadlock
task_protected_by_lock1_and_lock2() # Good
task_protected_by_lock2() # Bad: acquiring lock1 internally will cause deadlock
with
语句def f():
with lock1:
task_protected_by_lock1() # Good
with lock2:
task_protected_by_lock1_and_lock2() # Good
task_protected_by_lock2() # Bad: acquiring lock1 internally will cause deadlock
def f():
flag1 = False
flag2 = False
try:
lock1.acquire()
# Bad: SIGINT might be raised here
flag1 = True
task_protected_by_lock1()
lock2.acquire()
# Bad: SIGINT might be raised here
flag2 = True
task_protected_by_lock1_and_lock2()
lock1.release()
# Bad: SIGINT might be raised here
flag1 = False
task_protected_by_lock2()
lock2.release()
# Bad: SIGINT might be raised here
flag2 = False
except Exception as e:
if flag1:
lock1.release()
if flag2:
lock2.release()
raise e
def f():
try:
lock1.acquire()
task_protected_by_lock1()
lock2.acquire()
task_protected_by_lock1_and_lock2()
lock1.release()
# Suppose SIGINT happened here, just after another thread acquired lock1
task_protected_by_lock2()
lock2.release()
except Exception as e:
if lock1.locked():
lock1.release() # Bad: lock1 is NOT acquired by this thread!
if lock2.locked():
lock2.release()
raise e
def f():
with lock1:
task_protected_by_lock1()
# Bad: other thread might acquire lock1 and modify protected resources.
# This is NOT supposed to happen.
with lock1, lock2:
task_protected_by_lock1_and_lock2()
# Bad: other thread might acquire lock2 and modify protected resources.
# This is NOT supposed to happen.
with lock2:
task_protected_by_lock2()
我认为这就是 asyncio 的闪光点。
import asyncio
async def task_protected_by_lock1():
print("task_protected_by_lock1")
async def task_protected_by_lock1_and_lock2():
print("task_protected_by_lock1_and_lock2")
async def task_protected_by_lock2():
print("task_protected_by_lock2")
async def f():
try:
await task_protected_by_lock1()
await task_protected_by_lock1_and_lock2()
await task_protected_by_lock2()
except KeyboardInterrupt:
print("sigint")
except Exception as e:
print("handle the exception you like")
if __name__ == "__main__":
asyncio.run(f())