【问题标题】:Python threads with os.system() calls. Main thread doesn't exit on ctrl+c带有 os.system() 调用的 Python 线程。 ctrl+c 主线程不退出
【发布时间】:2012-12-22 17:12:18
【问题描述】:

在阅读之前请不要认为它是重复的,有很多关于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),它会正常工作。

【问题讨论】:

  • 您是否考虑过改用subprocess 模块?
  • 不要把它作为一个答案,因为它是一个丑陋的黑客,但对于任何搜索 os.system 导致你的脚本忽略 Ctrl+C 的人,你可以这样做 assert 0 == os.system("sleep 10")。这样,如果进程以 0 以外的任何值退出,则会引发 AssertionError。确实,您最好只使用子进程。

标签: python multithreading os.system keyboardinterrupt


【解决方案1】:

我不确定您使用的是什么操作系统和外壳。我用 zsh 描述 Mac OS X 和 Linux(bash/sh 应该类似)。

当您按下 Ctrl+C 时,所有程序都在当前终端 receive the signal SIGINT 的前台运行。在你的情况下,它是你的主要 python 进程和 os.system 产生的所有进程。

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

所以你的 python 线程都没有收到 SIGINT,只有子进程才能收到它。

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

您可以将os.system("sleep 10") 替换为subprocess.call(["sleep", "10"])subprocess.call() 不会让你的进程忽略 SIGINT。

【讨论】:

    【解决方案2】:

    当我第一次学习 python 多线程时,我遇到同样的问题的次数比我能倒数的还要多。

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

    我不完全确定 python 特定 sleep 和被称为 one 的操作系统之间的不同行为发生了什么,但我提供的补救措施应该适用于您想要的最终结果。只是提供一个猜测,被称为 one 的操作系统可能以不同的方式阻止解释器本身?

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

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

    【讨论】:

    • 感谢重播!但实际上似乎除了主要进程之外的所有进程都接收到信号。我不明白为什么会发生这种情况。有什么想法吗?
    猜你喜欢
    • 2015-11-14
    • 2017-07-03
    • 1970-01-01
    • 1970-01-01
    • 2014-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多