信号处理程序退出,程序为何继续运行?

2 投票
3 回答
1157 浏览
提问于 2025-04-15 13:32

看起来当我的信号处理程序结束时,我的程序仍然在继续运行。这一点很明显,因为即使在“日志完成,现在关闭”之后,仍然会出现异常。有人能解释一下这是为什么吗?请注意,这些函数已经简化了。

^Clog   Ctrl-C
backup  State: not_span 328, pos 22, all_cycles 19
backup  backup complete, you may force exit now
log     Done, close now
Traceback (most recent call last):
  File "singleEdger.py", line 219, in <module>
    mySingleEdger.outputAllCycles()
  File "singleEdger.py", line 141, in outputAllCycles
    r = self.returnCycle( self.dfs_tree, self.not_span[self.pos])
  File "singleEdger.py", line 72, in returnCycle
    udfs = nx.Graph(dfs)                    # The trick is to make it undirected
  File "/var/lib/python-support/python2.6/networkx/graph.py", line 86, in __init__
    convert.from_whatever(data,create_using=self)
  File "/var/lib/python-support/python2.6/networkx/convert.py", line 76, in from_whatever
    "Input is not a correct NetworkX graph."
networkx.exception.NetworkXError: Input is not a correct NetworkX graph.

这些是供参考的函数

    def sigHandler(self, arg1, arg2):
        out('log', 'Ctrl-C')
        self.backup()
        out('log', 'Done, close now')
        exit()


    def outputAllCycles(self):
        while self.pos < len(self.not_span):
            r = self.returnCycle( self.dfs_tree, self.not_span[self.pos])
            if r:
                self.all_cycles.append( r )
                for each in r:      # now it's [ (3,4), (5,6) ]
                    each = (sellHash(each[0]), sellHash( each[1]) )
                    self.outfo.write( each[0] +'\t'+ each[1] )
                    self.outfo.write( '\n')
                self.outfo.write( '\n')
            self.pos += 1
        out( "singleEdger", "outputAllCycles done")


    def backup(self):
        out( 'backup', 'State: not_span %i, pos %i, all_cycles %i' % ( len(self.not_span), self.pos, len(self.all_cycles)) )
        out( 'backup', 'backup complete, you may force exit now')

3 个回答

0

当你在运行代码时按下 ^C(通常是用来停止程序的快捷键),如果你的代码周围有一个 try/except 块,那么这个操作可能不会生效,因为 exit() 实际上会引发一个异常。你可以查看这个链接了解更多信息:http://bugs.python.org/issue8021

这种情况即使发生在你调用的库代码中,而不是你自己写的代码里,也同样适用。我在为一个机器人编写代码时,使用 urllib2.urlopen 在循环中连接网址时注意到了这一点;urllib2 的 do_open() 函数在尝试连接网址的代码周围也使用了 try/except 块。

0

还有一点你需要注意的是,在信号处理器中尽量避免进行耗时的操作(比如调用 backup() 可能会耗时很长)。更好的做法是设置一个标志,先从信号处理器返回,然后再进行处理。原因是(在Python中)信号处理器仍然会被注册,如果后续收到同类型的信号,它会打断当前的信号处理器,导致它再次执行。这可能不是你想要的结果。

或者你可以在处理器中忽略这个信号,比如:

import signal
def sigHandler(sig, frame):
    oldHandler = signal.signal(sig, signal.SIG_IGN)
    backup()    # lengthy processing here...
    signal.signal(sig, oldHandler)

但要注意,这样只会忽略同样的信号,其他信号仍然可能会打断你的处理。你的 backup() 是可重入的吗?

关于可重入性的讨论是相关的,虽然它是针对C语言的,而Python有些不同,比如信号不能被阻塞(除非你使用 ctypes)。

1

我觉得你的代码可能没有在运行。虽然异常输出的位置在代码中,但并不能保证它会在你最后的打印信息之前出现。异常输出是发送到错误输出(STDERR)的,而你的打印语句是发送到标准输出(STDOUT)的;在这个例子中,它们恰好都是写入同一个终端设备。两者的输出是独立缓冲的,所以输出的顺序并不是固定的;也就是说,你不能根据输出的相对位置来推断任何事情。

如果你在单元测试中放入打印语句,你也会看到同样的现象。

撰写回答