使用Python Interrupting Select中的信号处理程序的乐趣

时间:2011-10-15 02:32:52

标签: python multithreading signals

我正在编写一个编程项目 - 用Python编写基本的P2P文件共享应用程序。我正在使用两个线程:一个主要调用select并等待来自套接字列表和sys.stdin(接收类型命令)的输入,以及一个从队列中获取状态更新消息并打印它们的辅助线程。 (这是打印任何东西的唯一东西)

我还需要捕获标准SIGINT并处理它以优雅地退出。我有一个退出方法,这样做;输入'quit'作为命令工作得很好。所以在主线程中我尝试将此方法设置为SIGINT的处理程序。据我所知,该过程捕获信号并调用quit方法。帮助程序线程打印一条消息,确认它正在退出。但后来我从主线程中收到以下错误消息:

Traceback (most recent call last):
  File "peer.py", line 226, in <module>
    main()
  File "peer.py", line 223, in main
    p.run()
  File "peer.py", line 160, in run
    readables, writables, exceptions = select(self.sockets, [], [])
select.error: (4, 'Interrupted system call')

之后程序仍然退出。如果没有信号处理程序,发送SIGINT会给我以下内容:

Traceback (most recent call last):
  File "peer.py", line 225, in <module>
    main()
  File "peer.py", line 222, in main
    p.run()
  File "peer.py", line 159, in run
    readables, writables, exceptions = select(self.sockets, [], [])
KeyboardInterrupt

未能终止该程序;我必须停下来杀了它。这很令人困惑,因为SIGINT似乎只在我的自定义方法捕获时才会中断调用。 (只在打印队列上放置一条消息并设置“完成”变量)有谁知道这是怎么回事?试图同时使用信号处理程序和线程是一个坏主意吗?

2 个答案:

答案 0 :(得分:0)

我不确定使用信号处理程序来捕捉这种情况,但我在这里找到了基于* nix的系统处理这种情况的方法:http://code.activestate.com/recipes/496735-workaround-for-missed-sigint-in-multithreaded-prog/

简而言之(如果我正确地说):

在开始任何新线程之前,分叉子进程(使用os.fork)完成程序运行,并让父进程监视KeyboardInterrupt

当父级捕获键盘中断时,您可以使用os.kill终止子进程(现在可能已启动其他线程)。反过来,这将终止该子进程的任何线程。

答案 1 :(得分:0)

是的,昨晚我停止工作后,我意识到我确实希望它能够中断。据推测,它正在被执行信号处理程序中断。所以我只是抓住select.error并让它跳转到循环的末尾,它会立即退出并转到清理代码。