2013-03-12 81 views
4

的Python 2.7.3在Solaris 10上防止子线程死亡时线程subprocess.popen终止我的主脚本?

问题

  1. 当我的子进程有一个内部分割故障(核心)发行或用户通过一个外部SIGTERM或SIGKILL,杀死它从我的壳主程序的信号处理程序处理一个SIGTERM(-15),我的父程序退出。 这是真的吗?或者它是一个糟糕的python构建?

背景和代码

我有一个Python脚本,首先生成一个工人管理线程。工作管理线程然后产生一个或多个工作线程。我的主线程中还有其他内容,我无法阻止。我的管理线程的东西和工作线程是坚如磐石的。好几年我的服务,而无需重新启动,但然后我们有这个subprocess.Popen场景:

在工作线程的run方法,我使用:

class workerThread(threading.Thread): 
    def __init__(self) : 
     super(workerThread, self).__init__() 
    ... 
    def run(self) 
     ... 
     atempfile = tempfile.NamedTempFile(delete=False) 

     myprocess = subprocess.Popen(['third-party-cmd', 'with', 'arguments'], shell=False, stdin=subprocess.PIPE, stdout=atempfile, stderr=subprocess.STDOUT,close_fds=True) 
     ... 

我需要使用myprocess.poll()检查过程终止,因为我需要扫描atempfile,直到找到相关信息(文件可能> 1 GiB),并且由于用户请求或流程运行时间过长,我需要终止进程。一旦找到我正在查找的内容,我将停止检查stdout临时文件。在外部进程终止之后以及工作线程终止之前,我将对其进行清理。我需要stdin PIPE,以防我需要在孩子的标准输入流中注入一些交互响应。

在我的主程序中,如果我的主python程序以SIGTERM或SIGINT(Ctrl-C)结尾(如果从shell运行),我将为SIGIN和SIGTERM处理程序执行清理。

有没有人有线程中的子信号处理固体2.x配方? ctypes sigprocmask等

任何帮助将不胜感激。我只是在寻找一个'官方'配方或BEST hack,如果有的话。

注意

我使用Python的限制版本。我必须使用2.7.3。第三方-cmd是我没有源代码的程序 - 修改它是不可能的。

+0

欢迎来到SO。尽管我没有给你答案,但我建议你删除大部分“文字墙”。这可能会吓跑潜在的回答者。至少,将它分成几部分。 – xxmbabanexx 2013-03-12 01:34:00

+0

感谢您的回复。不知道如何编辑它,并得到我想要传达的信息。 – whistler 2013-03-12 01:43:39

+0

我编辑了您的问题,以帮助使其更具可读性。你不需要改变你写的内容,但是将它分成小节是有帮助的。 – xxmbabanexx 2013-03-12 01:47:35

回答

1

在描述中有很多东西看起来很奇怪。首先,你有几个不同的线程和过程。谁在崩溃,谁在接受SIGTERM,谁在接收SIGKILL,以及由于哪些操作?

第二:你父母为什么会收到SIGTERM?它不能被隐式发送。有人正在直接或间接调用kill给父进程(例如,通过杀死整个父进程组)。

第三点:当您处理SIGTERM时,程序如何终止?根据定义,如果程序没有处理,程序就会终止。如果处理完毕,则不会终止。真正发生的事情是什么?

建议:

$ cat crsh.c 
    #include <stdio.h> 

    int main(void) 
    { 
     int *f = 0x0; 

     puts("Crashing"); 
     *f = 0; 
     puts("Crashed"); 
     return 0; 
    } 
    $ cat a.py 

    import subprocess, sys 

    print('begin') 
    p = subprocess.Popen('./crsh') 
    a = raw_input() 
    print(a) 
    p.wait() 
    print('end') 
    $ python a.py 
    begin 
    Crashing 
    abcd 
    abcd 
    end 

这工作。没有信号传递给父母。你是否在程序中找到了问题?

如果问题是发送给多个进程的信号:您可以使用setpgid为孩子设置一个单独的进程组吗?

是否有任何理由创建临时文件?它是临时目录中创建的1 GB文件。为什么不用管道标准输出?如果你确实需要处理你的父程序中的信号(为什么你没有尝试/除了KeyboardInterrupt,例如?):可能signal()与多线程程序的未指定行为导致这些问题(例如,调度一个信号给一个不处理信号的线程)?

NOTES 
    The effects of signal() in a multithreaded process are unspecified. 

无论如何,尝试用更精确什么是你的程序的线程和进程来解释,他们做什么,如何进行信号处理程序设置和为什么,是谁发出的信号,谁接收,等等,等等等等等等。

+0

是的。你的例子确实有用,但是我的问题要复杂得多。谢谢你指出它很混乱。我更多地澄清了这些文字。我的popen发生在一个线程中,实际上是一个线程中的线程,如上所述。使用setpgid不起作用,因为我已经尝试使用preexec_fn,结果是一样的。管道标准输出可能导致标准输出管道中数据大小超过64k块时发生死锁。使用等待/与管道通信肯定会导致1GB数据的进程出现死锁。使用信号进行线程处理肯定会导致我的问题。 – whistler 2013-03-12 04:08:20

+1

在问题出现的地方创建一个最简单的示例。 – hdante 2013-03-12 18:32:30

+0

@whilster:[这个例子显示数据大于64K时没有死锁](https://gist.github.com/zed/3b4606d811fcf6530795) – jfs 2013-03-13 17:31:19