1

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

下面是程序。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]。这里出了什么问题?

4

2 回答 2

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()

于 2013-03-18T02:11:18.800 回答
0

我认为 [B] 只有在子进程花费不到 10 秒的情况下才有可能:主线程休眠 5 秒,然后workerjoin().

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

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

于 2013-03-18T02:34:26.533 回答