1

當我試圖終止運行在單獨的線程上運行的長時間運行的進程時,我遇到了問題。嘗試終止在線程上運行的python子進程時的行爲不一致

以下是程序。 WorkOne創建一個子進程並運行一個長時間運行的進程「adb logcat」來生成日誌行。我在main()中啓動WorkOne,等待5秒鐘並嘗試停止它。多次運行提供了多重輸出

import threading 
import time 
import subprocess 
import sys 

class WorkOne(threading.Thread): 

    def __init__(self): 
     threading.Thread.__init__(self) 
     self.event = threading.Event() 
     self.process = subprocess.Popen(['adb','logcat'], stdout=subprocess.PIPE, stderr=sys.stdout.fileno())  

    def run(self): 
     for line in iter(self.process.stdout.readline,''):    
      #print line 
      if self.event.is_set(): 
       self.process.terminate() 
       self.process.kill() 
       break; 
     print 'exited For' 

    def stop(self): 
     self.event.set() 

def main(): 

    print 'starting worker1' 
    worker1 = WorkOne() 
    worker1.start() 
    print 'number of threads: ' + str(threading.active_count()) 
    time.sleep(5) 
    worker1.stop() 
    worker1.join(5) 
    print 'number of threads: ' + str(threading.active_count()) 

if __name__ == '__main__': 
    main() 

有時我得到[A]:

starting worker1 
number of threads: 2 
number of threads: 2 
exited For 

有時候我[B]:

starting worker1 
number of threads: 2 
number of threads: 1 
exited For 

有時候我[C]:

starting worker1 
number of threads: 2 
number of threads: 2 

我想我應該期望得到[B]所有的時間即這裏出了什麼問題?

+1

由於您在'join()'調用中設置了超時,即使該線程已停止(例如,它正在等待'for'循環中的新行),也可以使線程保持活動狀態。 – 2013-03-18 01:57:56

+0

看起來像是這樣的問題,將for循環中的terminate和kill調用移至stop方法,現在我得到了我期望的一致輸出 – Harkish 2013-03-18 02:26:43

回答

0

我認爲[B]只有在子進程少於10秒時纔可能:主線程休眠5秒,之後workerjoin()的5秒超時內完成。

對於10秒或更長時間,即使在join()調用之後,worker仍然可以存活,因爲它有一個超時參數,可能發生與否。然後你可以得到[A](子過程幾秒鐘後完成)或[C](子過程稍後完成)。

爲了始終得到[B],請刪除join()的超時參數,以便主線程等待,直到worker完成(或確保通過將kill調用放置在循環外部10秒內終止進程)。

0

變化

 if self.event.is_set(): 
      self.process.terminate() 
      self.process.kill() 
      break; 

 if self.event.is_set(): 
      self.process.terminate() 
      self.process.wait() 
      break 

分號是一個大破綻,有一個問題就在這裏。

我猜測,如果沒有wait(),線程有時會過早地阻止work1.join(5)。在這種情況下,threading.active_count()返回2

而且,正如@ A.Rodas說,work1.join(5)應該work1.join(),以保證加盟不解鎖,直到work1完成。


順便說一句,我不知道爲什麼你會永遠想在繼承調用terminate然後kill。在Unix上,kill是更嚴重的終止形式。在Windows上,它們是相同的。所以如果你要打電話殺人,沒有必要調用終止。

由於您知道subprocess所調用的程序,因此您應該知道終止是否足以阻止它。

因此,您應該只需要一個:self.process.terminate()self.process.kill()

相關問題