Pylons中的信号处理

4 投票
2 回答
3143 浏览
提问于 2025-04-16 15:33

我有一个使用pylons框架的项目,需要定期更新一些内存中的数据结构。这些更新应该是根据需要进行的。于是我决定为此创建一个信号处理器。用户可以向主pylons线程发送SIGUSR1信号,项目会处理这个信号。

这个方法是可行的,但在处理完信号后,服务器会崩溃,并出现以下异常:

File "/usr/lib/python2.6/SocketServer.py", line 264, in handle_request
   fd_sets = select.select([self], [], [], timeout)
select.error: (4, 'Interrupted system call')

有没有办法解决这个问题呢?

谢谢大家。

2 个回答

2

这是一个解决方法,至少对我有效,来自一个12年前的python-dev邮件列表帖子

    while True:
        try:
            readable, writable, exceptional = select.select(inputs, outputs, inputs, timeout)
        except select.error, v:
            if v[0] != errno.EINTR: raise
        else: break

其实,具体的选择行并不重要……你的“fd_sets = select.select([self], [], [], timeout)”这一行应该是完全可以正常工作的。

关键是要检查是否出现了EINTR错误,如果捕捉到这个错误,就要重试或者循环执行。哦,对了,别忘了导入errno模块。

5

是的,这个是可以做到的,但用普通的Python库实现起来并不简单。这是因为Python会把所有操作系统的错误都转化为异常。不过,EINTR这个错误其实应该让你重新尝试之前的系统调用。每当你在Python中使用信号时,你都会偶尔遇到这个错误。

我有一段代码可以解决这个问题(叫做SafeSocket),它通过分叉Python模块来添加这个功能。不过,这个功能需要在每个使用系统调用的地方都加上去。所以说,虽然可以做到,但并不容易。不过你可以使用我的开源代码,这样可能会省去你几年的工作。;-)

基本的模式是这样的(实现为一个系统调用的装饰器):

# decorator to make system call methods safe from EINTR
def systemcall(meth):
    # have to import this way to avoid a circular import
    from _socket import error as SocketError
    def systemcallmeth(*args, **kwargs):
        while 1:
            try:
                    rv = meth(*args, **kwargs)
            except EnvironmentError as why:
                if why.args and why.args[0] == EINTR:
                    continue
                else:
                    raise
            except SocketError as why:
                if why.args and why.args[0] == EINTR:
                    continue
                else:
                    raise
            else:
                break
        return rv
    return systemcallmeth

你也可以把这个装饰器用在你的select调用周围。

撰写回答