在系统调用期间捕获/阻止SIGINT [英] Catching / blocking SIGINT during system call
问题描述
我编写了一个Web搜寻器,希望能够通过键盘停止它.我不希望程序在中断时消失.它需要先将其数据刷新到磁盘.我也不想捕获KeyboardInterruptedException
,因为持久性数据可能处于不一致状态.
I've written a web crawler that I'd like to be able to stop via the keyboard. I don't want the program to die when I interrupt it; it needs to flush its data to disk first. I also don't want to catch KeyboardInterruptedException
, because the persistent data could be in an inconsistent state.
我当前的解决方案是定义一个捕获SIGINT
并设置标志的信号处理程序;主循环的每次迭代都会在处理下一个网址之前检查此标志.
My current solution is to define a signal handler that catches SIGINT
and sets a flag; each iteration of the main loop checks this flag before processing the next url.
但是,我发现如果在发送中断时系统恰好正在执行socket.recv()
,我会得到:
However, I've found that if the system happens to be executing socket.recv()
when I send the interrupt, I get this:
^C
Interrupted; stopping... // indicates my interrupt handler ran
Traceback (most recent call last):
File "crawler_test.py", line 154, in <module>
main()
...
File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/socket.py", line 397, in readline
data = recv(1)
socket.error: [Errno 4] Interrupted system call
,该过程完全退出.为什么会这样?有什么方法可以防止中断影响系统调用吗?
and the process exits completely. Why does this happen? Is there a way I can prevent the interrupt from affecting the system call?
推荐答案
socket.recv()
调用C层中与POSIX兼容的基础recv
函数,而该函数将在C层中返回错误代码EINTR
.进程在等待recv()
中的传入数据时接收到SIGINT
.可以在C端使用此错误代码(如果您使用C进行编程)来检测recv()
返回不是因为套接字上有更多可用数据,而是因为进程收到了SIGINT
.无论如何,此错误代码被Python转换为异常,并且由于从未捕获到它,因此它会以看到的回溯终止应用程序.解决方案是简单地捕获socket.error
,检查错误代码,如果错误代码等于errno.EINTR
,则静默忽略该异常.像这样:
socket.recv()
calls the underlying POSIX-compliant recv
function in the C layer, which, in turn, will return an error code EINTR
when the process receives a SIGINT
while waiting for incoming data in recv()
. This error code can be used on the C side (if you were programming in C) to detect that recv()
returned not because there is more data available on the socket but because the process received a SIGINT
. Anyway, this error code is turned into an exception by Python, and since it is never caught, it terminates your application with the traceback you see. The solution is simply to catch socket.error
, check the error code and if it is equal to errno.EINTR
, ignore the exception silently. Something like this:
import errno
try:
# do something
result = conn.recv(bufsize)
except socket.error as (code, msg):
if code != errno.EINTR:
raise
这篇关于在系统调用期间捕获/阻止SIGINT的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!