尝试终止在线程上运行的python子进程时的行为不一致

时间:2013-03-18 01:30:45

标签: python multithreading subprocess terminate long-running-processes

当我尝试终止运行在单独线程上运行的长时间运行进程时,我遇到了问题。

以下是该计划。 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]。这里出了什么问题?

2 个答案:

答案 0 :(得分: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上,它们是相同的。因此,如果您打算调用kill,则无需调用terminate。

由于你知道subprocess调用的程序,你也应该知道终止是否足以阻止它。

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

答案 1 :(得分:0)

我认为[B]只有在子进程少于10秒时才有可能:主线程休眠5秒,之后workerjoin()的5秒超时内完成。

对于10秒或更长时间,worker即使在join()调用之后也可以存活,因为它有超时参数,这可能发生与否。然后你可以得到[A](子流程几秒钟后完成)或[C](子流程很快完成)。

要获得[B],请删除join()的超时参数,以便主线程等待worker完成(或确保在10秒内通过将kill调用置于循环)。