2014-02-06 101 views
0

在您閱讀上,要知道我是新來的Python和非常新的線程,因此原諒我,如果我誤會線程如何工作或做一個菜鳥錯誤:PPython的線程 - 管理線程終止與主線程

我的目標

簡短說明:

  1. 主線程(一)確實有些東西(如打印!「開始」)
  2. 主線程產生一個新的線程(b)在第一次印「線程b 開始「然後永遠打印x + 1(1,2,3 ...)
  3. 主線打印「Woop!」
  4. 然後在達到主線程結束,則終止本身和 然後切換到線程B使B中的主線程
  5. 方案現在正在運行的線程B作爲主線程所以僅僅是 印刷X + 1永遠和一個已經被人遺忘,不再 相關
  6. 按Ctrl + C將終止線程b,有效,整個程序 將被終止,因爲線程不存在了

這裏就是我有這麼(基本):

import threading, time 

def printCount(): 
    print "Thread B started" 
    x = 0 
    while True: 
     time.sleep(1) 
     x = x + 1 
     print x 

## User Code ## 
print "begin!" 
threadB = threading.Thread(target=printCount) 
threadB.start() 
print "woop!" 

的要求是:

  • 我不想太多的所有修改「用戶守則」關口下方。我 當然不希望它包裝在一個類,函數或它自己的 螺紋
  • 按Ctrl + C在任何時候應該終止整個程序 沒有線程保持運行(使用類似:except
    KeyboardInterrupt: os._exit(1))
    內用戶代碼是罰款
  • 一個線程可以繼續運行,而不是讓線程b的主要 線程,但在這種情況下,我不想代碼來處理按Ctrl + C 終止用戶代碼中的整個程序部分

This例子不是我的實際目標,只是我遇到的問題的簡化版本。我正在嘗試構建一個IRC框架,用戶可以在其中導入它並非常簡單地使用API​​,而無需使用線程和中斷等來混淆他們自己的代碼。這就是爲什麼使用戶代碼儘可能乾淨至關重要。

該框架將允許用戶創建一個永久運行的IRC bot,監聽命令,同時允許用戶添加自己的命令。如果你感興趣的話,Github鏈接是here(這是非常WIP atm)。

回答

1

你不能「切換」線程。所以一旦你完成了你的主線程,你必須等待其他線程終止使用方法join。但要注意的是:

  • 由於join方法不是可中斷的KeyboardInterrupt,您需要通過指定超時和循環檢測用戶中斷。
  • 既然你不能強迫一個線程終止,你必須實現使用threading.Event例如停止mecanism
  • 你還需要使用threading.Lock,以防止對共享資源併發訪問,如sys.stdout(用來當您打印)

我收集這些方面在一個名爲ThreadHandler類,請看看:

import threading, time 

def printCount(lock, stop): 
    with lock: 
     print "Thread B started" 
    x = 0 
    while not stop.is_set(): 
     time.sleep(1) 
     x = x + 1 
     with lock: 
      print x 

class ThreadHandler(): 
    STEP = 0.2 

    def __init__(self, target): 
     self.lock = threading.Lock() 
     self.stop = threading.Event() 
     args = (self.lock, self.stop) 
     self.thread = threading.Thread(target=target, args=args) 

    def start(self): 
     self.thread.start() 

    def join(self): 
     while self.thread.is_alive(): 
      try: 
       self.thread.join(self.STEP) 
      except KeyboardInterrupt: 
       self.stop.set() 

## User Code ## 
print "begin!" 
handler = ThreadHandler(target=printCount) 
handler.start() 
with handler.lock: 
    print "woop!" 
handler.join() 
1

昨天寫一張紙條上的另一個問題具有類似的問題,這是一個檢查,你可以在子線程「b」的實施:

代替while 1:做到以下幾點:

def printCount(): 
    main = None 
    for t in threading.enumerate(): 
     if t.name == 'MainThread': 
      main = t 
    print "Thread B started" 
    x = 0 
    while main and main.isAlive(): 
     time.sleep(1) 
     x = x + 1 
     print x 

會在全局範圍內存儲main是一個不錯的主意,因爲所有線程都可以使用,而不必每次啓動子線程時都要查看主線程。 但是這會做你的例子中的工作。

main將朝着你的主線程手柄通過所有線程(.enumerate()),然後將名爲「MainThread」線程進入main迭代,然後調用main.isAlive()檢查它是否仍在運行。 如果mainNoneFalse或者.isAlive()回報False將表明線程要麼是不存在的或死的,關閉你的子線程:)

+1

我想包含printCount繼續永遠運行線程,但這間esting! – Jazcash

+0

@Jazcash哦,我的壞,我以爲我讀到你想要的線程不會永遠運行:) – Torxed

0

不能切換這樣的線程。它不這樣工作。

但是你可以使用信號與全局標誌ALIVE

import threading, time, signal 

ALIVE = True 

def handle_sigint(signum, frame): 
    global ALIVE 
    ALIVE = False 

signal.signal(signal.SIGINT, handle_sigint) 

def printCount(): 
    print "Thread B started" 
    x = 0 
    while ALIVE: # <--- note the change 
     time.sleep(1) 
     x = x + 1 
     print x 

## User Code ## 
print "begin!" 
threadB = threading.Thread(target=printCount) 
threadB.start() 
print "woop!" 

signal.pause() # <--- wait for signals 

現在它將會優雅地按下CTRL + C後退出。

+0

這很不錯,但你有用戶代碼中的signal.pause()。也許我應該創造一個更好的例子。主線程結束後是否有辦法啓動線程? – Jazcash

+1

@Jazcash你可以從任何線程啓動線程。但是,您需要主線程來處理像CTRL + C這樣的信號。如果主線程終止,那麼你不會捕獲該信號。 – freakish