我正在用python编写程序。我希望从stdin读取并处理sigchld。我希望处理任何一个输入,而不是旋转(推测性地为输入采样)。
我无法接听每次通话时被信号中断的系统调用。
我是以错误的方式来做这件事的吗?我可以在没有尝试/除外的情况下使用它吗?
我主要担心的不是尝试/除了我在代码中到目前为止。但是,在程序中的其他代码行中我将需要数百个。它对我来说似乎并不模块化。
以下是一些测试代码:
#!/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
答案 0 :(得分:6)
是的,你正是以正确的方式解决这个问题。 (好吧,我可能会使用select
或poll
而不是epoll
,因为那时你的代码可以移植到非Linux平台......)
我假设在这里对两个或更多fds进行轮询对你的设计来说是必然的。如果你只添加epoll循环来处理信号,那么这部分就没有必要;您只需要围绕read
调用的简单EINTR循环。但是,一旦你有一个用于其他目的的管道,把它连接起来就像信号唤醒管道是一个合理的事情,然后你的,你所做的一切都隐含在从多个fds读取。
无论哪种方式,你都无法避免try
块。 (这不是真的。你可以始终使用sigblock
/ sigprocmask
/等来阻止信号 - 它们不在Python的signal
模块中,但是您可以随时ctypes
他们。但是,您通常需要更多代码,使用try
/ finally
而不是try
/ except
,以及您的代码变得越来越难以调试,因此除了在处理无法中断且必须被sigblocked的代码的少数情况下,沿着这条路走下去并没有什么意义。)
这是POSIX的标准功能,许多系统调用可以被信号中断,在这种情况下,它们会因EINTR而失败。
大多数特定平台将可以中断的调用列表限制为比POSIX允许的更小的集合,因此您必须查看linux文档以确定究竟是什么和不是EINTR安全的,但是epoll
方法系列以及read
/ recv
/ write
/ send
和朋友几乎肯定是不安全的。
使用siginterrupt
可能有所帮助,但它无法解决问题。特别是,不需要调用来重新启动而不是中断,并且在某些情况下,他们需要中断或完成部分结果而不是重新启动。我很确定select
和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
的任何地方,请致电dopoll
。
答案 1 :(得分:1)
我编写了一个python库,它将信号显示为流,因此我可以使用select / poll / epoll等。它使用libc(Gnu C库)来完成艰苦的工作。希望它有用。
https://github.com/richard-delorenzi/pysigstream
如果你想改进它,那么你可以分叉,请发送拉动请求。