什么时候Python程序没有响应中断?

我有一个运行在Linux上的Python3守护进程。 这是一个正常的单线程进程在后台运行,并在主循环中执行select.select() ,然后处理I / O。 有时(一个月大约1或2次),停止响应。 当它发生时,我想debugging这个问题。

我已经尝试过pyrasite ,但是没有成功,因为守护进程的stdin / stdout被redirect到/dev/null设备,pyrasite使用这个stdin / stdout,而不是从它开始的控制台。

所以我添加了一个SIGUSR1信号处理程序来logging堆栈跟踪。 正常工作正常。

今天我冻结了 ps显示,守护进程处于“S”(可中断睡眠)状态。 排除繁忙的循环。

服务器不响应SIGUSRSIGINT (用于closures)。

我想至less有一些提示,那里正在发生什么。

在什么情况下,睡眠的Python3 Linux进程不处理它应该处理的中断?


更新:

我最终可以重现这个问题。 添加了很多debugging信息之后,我发现了一个即将解决的竞争条件。

当守护进程没有响应时,它在os.read(p)处睡眠,其中p是新pipe道的读端(参见: os.pipe ),其中没有人写入。

但是,我所有的编写简单演示程序的尝试都失败了。 当我试图从一个空pipe读取时,程序按预期被阻塞,但是可能像往常一样被中断(从SIGINT其他terminal中死亡)。 这个谜尚未解决。


UPDATE2:

最后一些代码! 我故意select了低级系统调用。

 import os import time import signal import sys def sighandler(*unused): print("got signal", file=sys.stderr) print("==========") signal.signal(signal.SIGUSR1, sighandler) pid = os.getpid() rfd, wfd = os.pipe() if os.fork(): os.close(wfd) print("parent: read() start") os.read(rfd, 4096) print("parent: read() stop") else: os.close(rfd) os.kill(pid, signal.SIGUSR1) print("child: wait start") time.sleep(3) print("child: wait end") 

如果你运行这么多的时间,你会得到这个:

 parent: read() start got signal child: wait start child: wait end parent: read() stop 

这很好,但有时你会看到这样的:

 parent: read() start child: wait start child: wait end got signal parent: read() stop 

这里发生了什么事情:

  1. 父母从pipe道开始读取
  2. 孩子向父母发送信号。 父母必须收到这个信号,但似乎是“不知何故推迟了”
  3. 孩子等待
  4. 小孩出口,pipe道自动closures
  5. 父母的读取操作以EOF结束
  6. 现在处理信号

现在,由于我的程序中有一个错误,信号在步骤2中被接收到,但是EOF没有被传送,所以读取没有完成,步骤6(信号处理)从未到达。

这是我能够提供的所有信息。