2013-01-08 192 views
4

請不要在重讀之前將它看作是重複的,關於multithreadingkeyboard interrupt有很多問題,但我沒有發現任何考慮os.system,它看起來像是重要。使用os.system()調用的Python線程。主線程不會退出ctrl + c

我有一個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)它工作正常。

+0

你有沒有考慮過使用[subprocess](http://docs.python.org/2/library/subprocess.html)模塊呢? – moooeeeep

+0

不要把這個作爲一個答案,因爲它是一個醜陋的黑客,但對於任何人爲了os.system googleing導致你的腳本忽略Ctrl + C,你可以'assert 0 == os.system(「sleep 10」)'。這樣,如果進程退出0以外的任何內容,將引發一個AssertionError。實際上,你使用子進程可能會更好。 –

回答

4

我不知道什麼樣的操作系統和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()。 Python os.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。

1

當我第一次學習python多線程時,我有過這個問題的次數超過了我可以計數的次數。

在循環內添加睡眠呼叫使您的主線程阻塞,這將允許它仍然可以聽到並承認異常。你想要做的就是利用Event類來設置你的子線程中的一個事件,它將作爲一個退出標誌來中斷執行。您可以在您的KeyboardInterrupt異常中設置此標誌,只需在主線程中添加except子句即可。

我不完全確定python特定睡眠和os之間的不同行爲是怎麼回事,但我提供的補救措施應該適用於您期望的最終結果。只是提供一個猜測,所謂的一個os可能會以不同的方式阻止解釋器本身?請注意,通常在需要線程的大多數情況下,主線程將繼續執行某種東西,在這種情況下,隱藏您簡單示例中的「睡眠」。

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

+0

感謝您的重播!但實際上似乎除了主要接收信號之外的所有過程。我不明白爲什麼會發生這種情況。任何想法? – Shamdor