使用os.system()调用的Python线程。主线程在ctrl时不退出+

2024-04-30 03:23:36 发布

您现在位置:Python中文网/ 问答频道 /正文

在阅读之前请不要认为它是重复的,有很多关于multithreadingkeyboard interrupt的问题,但是我没有找到任何考虑的os.system,看起来它很重要。

我有一个python脚本,它在工作线程中进行一些外部调用。 如果我按ctrl+c,我希望它退出,但它看起来像是主线程忽略了它。

像这样的:

from threading import Thread
import sys
import os

def run(i):
    while True:
        os.system("sleep 10")
        print i

def main():
    threads=[]
    try:
        for i in range(0, 3):
            threads.append(Thread(target=run, args=(i,)))
            threads[i].daemon=True
            threads[i].start()
        for i in range(0, 3):
            while True:
                threads[i].join(10)
                if not threads[i].isAlive():
                    break

    except(KeyboardInterrupt, SystemExit):
        sys.exit("Interrupted by ctrl+c\n")


if __name__ == '__main__': 
    main() 

令人惊讶的是,如果我将os.system("sleep 10")更改为time.sleep(10),它就可以正常工作。


Tags: runinimporttrueforosmaindef
2条回答

我不知道你用的是什么操作系统和shell。我用zsh描述Mac OS X和Linux(bash/sh的行为应该类似)。

当您按下Ctrl+C时,当前终端receive the signal SIGINT中前台运行的所有程序。在您的例子中,它是您的主python进程和os.system生成的所有进程。

由os.system生成的进程然后终止其执行。通常当python脚本接收到SIGINT时,它会引发KeyboardInterrupt异常,但是主进程会忽略SIGINT,因为os.system()。Pythonos.system()calls the Standard C functionsystem(),这使得调用进程忽略SIGINT(man Linux/man Mac OS X)。

因此,您的python线程都不接收SIGINT,只有子进程才能获得它。

当删除os.system()调用时,python进程停止忽略SIGINT,您将得到KeyboardInterrupt

您可以用subprocess.call(["sleep", "10"])替换os.system("sleep 10")subprocess.call()不会使进程忽略SIGINT。

当我第一次学习python多线程时,我遇到同样的问题的次数已经超过了我可以倒数的次数。

在循环中添加sleep调用将使您的主线程阻塞,这将允许它仍然听到并接受异常。您要做的是利用Event类在子线程中设置一个事件,该事件将用作中断执行的退出标志。您可以在KeyboardInterrupt异常中设置此标志,只需将该异常的except子句放在主线程中。

我不完全确定python特定的sleep和被称为one的os之间的不同行为是怎么回事,但是我提供的补救方法应该能达到您所期望的最终结果。只是猜测一下,名为one的操作系统可能会以不同的方式阻塞解释器本身?

请记住,通常在需要线程的大多数情况下,主线程将继续执行某些操作,在这种情况下,您的简单示例中的“休眠”将被隐含。

http://docs.python.org/2/library/threading.html#event-objects

相关问题 更多 >