多线程程序中的异步信号似乎没有被Python正确处理。但是,我想我应该在这里检查一下,看看有没有人能发现我违反了一些原则,或者误解了一些概念。
我在SO上找到了类似的帖子,但似乎没有一个是完全相同的。
场景是:我有两个线程,读线程和写线程(主线程)。写线程写入读线程轮询的管道。这两个线程是使用threading.Event()原语(我假设它是使用pthread_cond_wait实现的)来协调的。主线程在Event上等待,而读取器线程最终设置它。
但是,如果我想在主线程等待Event时中断程序,就不会异步处理KeyboardInterrupt。
下面是一个小程序来说明我的观点:
#!/usr/bin/python
import os
import sys
import select
import time
import threading
pfd_r = -1
pfd_w = -1
reader_ready = threading.Event()
class Reader(threading.Thread):
"""Read data from pipe and echo to stdout."""
def run(self):
global pfd_r
while True:
if select.select([pfd_r], [], [], 1)[0] == [pfd_r]:
output = os.read(pfd_r, 1000)
sys.stdout.write("R> '%s'\n" % output)
sys.stdout.flush()
# Suppose there is some long-running processing happening:
time.sleep(10)
reader_ready.set()
# Set up pipe.
(pfd_r, pfd_w) = os.pipe()
rt = Reader()
rt.daemon = True
rt.start()
while True:
reader_ready.clear()
user_input = raw_input("> ").strip()
written = os.write(pfd_w, user_input)
assert written == len(user_input)
# Wait for reply -- Try to ^C here and it won't work immediately.
reader_ready.wait()使用'./bug.py‘启动程序,并在提示符处输入一些输入。一旦你看到阅读器回复带有前缀'R>',尝试使用^C中断。
我所看到的(Ubuntu Linux10.10,Python2.6.6)是在阻塞reader_ready.wait()返回之后才处理^C。我期望看到的是^C被异步引发,导致程序终止(因为我没有捕捉到KeyboardInterrupt)。
这看起来像是一个人为的例子,但我在一个真实的程序中遇到了这个问题,在这个程序中,time.sleep(10)被实际的计算所取代。
我是不是做错了什么,比如误解了预期的结果是什么?
编辑:我刚刚也测试了Python 3.1.1,同样的问题也存在。
发布于 2011-11-19 01:51:25
threading._Event对象的wait()方法实际上依赖于thread.lock的acquire()方法。但是,thread documentation声明锁的acquire()方法不能被中断,任何KeyboardInterrupt异常都将在锁释放后处理。
因此,基本上,这是预期的工作。实现此行为的线程对象在某些时候(包括队列)依赖于锁,因此您可能希望选择另一条路径。
发布于 2015-06-15 00:14:09
或者,您也可以使用signal模块的pause()函数来代替reader_ready.wait()。signal.pause()是一个阻塞函数,当进程接收到信号时,它将被解除阻塞。在您的情况下,当按下^C时,SIGINT SIGINT信号将解除对该功能的阻止。
根据文档,该功能不适用于Windows。我在Linux上对它进行了测试,它可以正常工作。我认为这比使用超时的wait()要好。
https://stackoverflow.com/questions/8184051
复制相似问题