使用os.system()调用的Python线程.主线程不会在ctrl + c上退出

Sha*_*dor 5 python multithreading os.system keyboardinterrupt

请不要在阅读之前认为它是重复的,有很多关于multithreading和的问题keyboard 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() 
Run Code Online (Sandbox Code Playgroud)

出人意料的是,如果我改变它工作正常os.system("sleep 10")time.sleep(10).

dim*_*-an 6

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

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

由 os.system 产生的进程然后终止它们的执行。通常当 python 脚本收到 SIGINT 时,它会引发 KeyboardInterrupt 异常,但您的主进程会忽略 SIGINT,因为os.system(). Pythonos.system() 调用标准 C 函数 system(),这使得调用进程忽略 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。