python信号,中断系统调用

2024-03-08

我正在用 python 编写一个程序。我希望从 stdin 读取并处理 sigchld。我想在输入时处理任一输入,而不旋转(推测性地对输入进行采样)。

我无法在每次调用时捕捉到被信号中断的系统调用。

我是否以错误的方式处理这个问题?我可以在不尝试/例外的情况下让它工作吗?

我主要担心的不是到目前为止我在代码中的 try/ except 。但是我在程序中的其他代码行中将需要所有数百个。对我来说它似乎不是模块化的。

这是一些测试代码:

#!/usr/bin/python

from time import sleep
import select
import signal
import fcntl
import os
import sys

pipe_r, pipe_w = os.pipe()
flags = fcntl.fcntl(pipe_w, fcntl.F_GETFL, 0)
flags = flags | os.O_NONBLOCK
fcntl.fcntl(pipe_w, fcntl.F_SETFL, flags)

signal.signal(signal.SIGCHLD, lambda x,y: None)
signal.signal(signal.SIGALRM, lambda x,y: None)
signal.siginterrupt(signal.SIGCHLD,False) #makes no difference
signal.siginterrupt(signal.SIGALRM,False) #makes no difference
signal.set_wakeup_fd(pipe_w)
signal.setitimer(signal.ITIMER_REAL, 2, 2)

poller = select.epoll()
poller.register(pipe_r, select.EPOLLIN)
poller.register(sys.stdin, select.EPOLLIN)

print "Main screen turn on"
while True:
    events=[]
    try:
        events = poller.poll()
        try:
            for fd, flags in events:
                ch=os.read(fd, 1)
                if fd==pipe_r:
                    sys.stdout.write( "We get Signal" )
                if fd==sys.stdin.fileno():
                    sys.stdout.write( ch )
                sys.stdout.flush()
        except IOError as e:
            print "exception loop" + str(e)
    except IOError as e:
        print "exception poll" + str(e)

版本:

#python --version
python 2.7.3
#uname -a
Linux richard 3.2.0-32-generic #51-Ubuntu SMP Wed Sep 26 21:33:09 UTC 2012 x86_64 x86_64 x86_64 GNU/Linux

是的,你正在以正确的方式处理这件事。 (嗯,我可能会用select or poll代替epoll,因为这样你的代码将可以移植到非 Linux 平台......)

我在这里假设轮询两个或多个文件描述符对于您的设计来说本质上是必要的。如果您只添加了 epoll 循环来处理信号,那么该部分就不是必需的;你所需要的只是一个简单的 EINTR 循环read称呼。但是,一旦您有一个用于其他目的的管道,将其连接为信号唤醒管道是合理的事情,然后您和您正在做的所有其他事情都隐含在从多个 fd 读取中。

不管怎样,你确实无法避免try块。 (这并不完全正确。你can始终阻止信号sigblock/sigprocmask/etc.——它们不在 Python 中signal模块,但您始终可以ctypes他们。但是你通常需要稍微多一点的代码,try/finally代替try/except,并且您的代码变得更难调试,因此沿着这条路走下去没有多大意义,除非您正在处理无法中断且必须进行 sigblock 的代码。)

POSIX 的一个标准功能是许多系统调用可以被信号中断,在这种情况下它们会因 EINTR 而失败。

大多数特定平台将可中断的调用列表限制为比 POSIX 允许的更小的集合,因此您必须查看 linux 文档才能确切确定什么是 EINTR 安全的,什么不是 EINTR 安全的,但是epoll方法族,以及read/recv/write/send和朋友们,几乎肯定会不安全。

Using siginterrupt你这样做可能会有所帮助,但并不能解决问题。特别是,不需要调用来重新启动而不是中断,并且在某些情况下需要中断或完成部分结果而不是重新启动。我相当确定select and poll永远不会重新启动,所以很有可能epoll家人也不是,但你必须检查一下。无论如何,大多数 BSD 衍生品都默认重新启动,因此如果 linux 是相同的,则您无需更改任何内容。

Python 可以用隐式 EINTR 循环来包装所有这些,并且我相信一些更高级别的方法(例如sendall) 这样做,但较低级别的方法不这样做。但你可以自己把事情包起来。例如(在我的脑海中,未经测试):

def dopoll(poller):
    while True:
        try:
            return poller.poll()
        except IOError as e:
            if e.errno != EINTR:
                raise

然后,无论你打电话到哪里poll, call dopoll反而。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

python信号,中断系统调用 的相关文章

随机推荐