在线程中捕获中断的系统调用
Posted
技术标签:
【中文标题】在线程中捕获中断的系统调用【英文标题】:Catch Interrupted system call in threading 【发布时间】:2012-11-16 09:47:29 【问题描述】:我有一个使用设想框架的客户端-服务器应用程序,我正在使用线程来处理连接,这是代码中的一个标记
....
SocketServer.TCPServer.allow_reuse_address = True
self.server = TCPFactory( ( HOST, PORT ), TCPRequestHandler, self.application)
self.server_thread = threading.Thread( target = self.server.serve_forever )
self.server_thread.setDaemon( True )
self.server_thread.start()
class TCPFactory( SocketServer.ThreadingTCPServer ):
def __init__( self, server_address, RequestHandlerClass, application ):
SocketServer.ThreadingTCPServer.__init__( self, server_address, RequestHandlerClass )
self.application = application
class TCPRequestHandler( SocketServer.BaseRequestHandler ):
""""""
def setup( self ):
.....
在设想框架中,我调用了open_file( )
函数,它给了我们一个弹出窗口,但是当这个窗口出现时,我收到以下错误
Exception in thread Thread-2:
Traceback (most recent call last):
File "/usr/lib/python2.7/threading.py", line 551, in __bootstrap_inner
self.run()
File "/usr/lib/python2.7/threading.py", line 504, in run
self.__target(*self.__args, **self.__kwargs)
File "/usr/lib/python2.7/SocketServer.py", line 225, in serve_forever
r, w, e = select.select([self], [], [], poll_interval)
error: (4, 'Interrupted system call')
我该如何处理这个错误?
【问题讨论】:
代码中的 sn-p 不是很有帮助,因为它不必对您粘贴在下面的堆栈跟踪做任何事情(也与您提到的对open_file()
的调用无关)。你知道是什么中断了跟踪中提到的select()
调用吗?
通常,“系统调用中断”是一个错误,应该通过重试系统调用来处理。我不清楚为什么 select.select() 不进行重试。您需要捕获“select.error”,检查其 errno 属性是否等于 errno.EINTR,如果是,则忽略它。
【参考方案1】:
Armin Rigo 评论后,我修改了 SockeServer.py
def serve_forever(self, poll_interval=0.5):
"""Handle one request at a time until shutdown.
Polls for shutdown every poll_interval seconds. Ignores
self.timeout. If you need to do periodic tasks, do them in
another thread.
"""
self.__is_shut_down.clear()
try:
while not self.__shutdown_request:
# XXX: Consider using another file descriptor or
# connecting to the socket to wake this up instead of
# polling. Polling reduces our responsiveness to a
# shutdown request and wastes cpu at all other times.
try:
r, w, e = select.select([self], [], [], poll_interval)
except select.error as ex:
#print ex
if ex[0] == 4:
continue
else:
raise
if self in r:
self._handle_request_noblock()
finally:
self.__shutdown_request = False
self.__is_shut_down.set()
【讨论】:
【参考方案2】:我刚刚在一个程序中添加了一个小型 httpd 服务器时遇到了类似的问题,它接收来自其他进程的各种信号。在玩弄之后,我想出了一个简单的解决方案,可以避免实际修改 stlib 代码,但我认为这有点冒险。我只是将 serve_forever 调用包装在一个循环中,该循环捕获并忽略套接字错误:
def non_int_serve_forever(self, poll_interval=0.5):
while 1:
try:
self.serve_forever(poll_interval=poll_interval)
break
except select.error:
pass
这消除了针对不同版本的 SocketServer.py 需要不同解决方案的风险,但 serve_forever() 应该可以多次重新启动并不明显,即使它现在似乎可以工作。
有什么想法吗?
【讨论】:
以上是关于在线程中捕获中断的系统调用的主要内容,如果未能解决你的问题,请参考以下文章
抢占式内核中,线程在系统调用过程中被抢占,然后又被重新调度时,如何返回至被中断的系统调用的
在Windows或Linux等高级系统里,驱动程序是以线程的形式独立运行,还是做为过程被线程调用运行?