如何检测线程是否已停止,然后重新启动它?

7

我有一个应用程序,它启动了一系列的线程。偶尔会发生其中一个线程死亡(通常是由于网络问题)。我该如何正确检测线程崩溃并重新启动该线程?以下是示例代码:

import random
import threading
import time

class MyThread(threading.Thread):
    def __init__(self, pass_value):
        super(MyThread, self).__init__()
        self.running = False
        self.value = pass_value

    def run(self):
        self.running = True

        while self.running:
            time.sleep(0.25)

            rand = random.randint(0,10)
            print threading.current_thread().name, rand, self.value
            if rand == 4:
                raise ValueError('Returned 4!')


if __name__ == '__main__':
    group1 = []
    group2 = []
    for g in range(4):
        group1.append(MyThread(g))
        group2.append(MyThread(g+20))


    for m in group1:
        m.start()

    print "Now start second wave..."

    for p in group2:
        p.start()

在这个例子中,我启动了4个线程,然后又启动了4个线程。每个线程随机生成一个介于0和10之间的int。如果该int是4,则会引发异常。请注意,我没有加入这些线程。我希望group1和group2线程列表都在运行。我发现,如果我加入了这些线程,它将等待直到线程终止。我的线程应该是一个守护进程,因此应该很少(如果有的话)遇到这个示例代码显示的ValueError异常,并且应该一直运行。通过加入它,下一组线程不会开始。
如何检测特定线程已死亡并重新启动该线程?
在我的group2循环结束后,我尝试了以下循环。
while True:
    # Create a copy of our groups to iterate over, 
    # so that we can delete dead threads if needed
    for m in group1[:]:
        if not m.isAlive():
            group1.remove(m)
            group1.append(MyThread(1))

    for m in group2[:]:
        if not m.isAlive():
            group2.remove(m)
            group2.append(MyThread(500))

    time.sleep(5.0)

我从这里获取了此方法。

问题在于isAlive()似乎总是返回True,因为线程从未重新启动。

编辑

在这种情况下,使用多进程是否更合适?我找到了这个教程。如果需要重新启动进程,使用单独的进程是否更合适?似乎重新启动线程很困难。

评论中提到我应该对is_active()和线程进行比较。我没有在文档中看到这一点,但我确实看到了我目前正在使用的isAlive。如上所述,它返回True,因此我无法看到线程已死亡。


你可以检查:mythread.isActive() 或 mythread.is_active()。它只是检查线程是否处于活动状态(即运行 run() 方法)。 - Luis Masuelli
你必须跟踪你的线程实例才能使其工作。你也可以使用你的“running”属性来终止它们。 - Luis Masuelli
@LuisMasuelli 我没有用我的 group1group2 列表来跟踪它吗? - NewGuy
我的错。是的,你可以访问它们并逐个检查,看看.running是否为False,或者更准确地说,is_active()是否为False。 - Luis Masuelli
2个回答

7

我遇到了类似的问题,并偶然发现了这个问题。我发现join方法有一个超时参数,而is_alive方法在线程加入后返回False。所以我对每个线程进行以下审计:

def check_thread_alive(thr):
    thr.join(timeout=0.0)
    return thr.is_alive()

这个可以为我检测线程结束。


2
您可以在预计程序崩溃的位置(如果它可能出现在任何地方,则可以在整个运行函数周围)放置try except,并具有其状态的指示变量。
因此,类似于以下内容:
class MyThread(threading.Thread):
    def __init__(self, pass_value):
        super(MyThread, self).__init__()
        self.running = False
        self.value = pass_value
        self.RUNNING = 0
        self.FINISHED_OK  = 1
        self.STOPPED = 2
        self.CRASHED = 3
        self.status = self.STOPPED

    def run(self):
        self.running = True    
        self.status = self.RUNNING


        while self.running:
            time.sleep(0.25)

            rand = random.randint(0,10)
            print threading.current_thread().name, rand, self.value

            try:
                if rand == 4:
                    raise ValueError('Returned 4!')
            except:
                self.status = self.CRASHED

然后您可以使用循环:
while True:
    # Create a copy of our groups to iterate over, 
    # so that we can delete dead threads if needed
    for m in group1[:]:
        if m.status == m.CRASHED:
            value = m.value
            group1.remove(m)
            group1.append(MyThread(value))

    for m in group2[:]:
        if m.status == m.CRASHED:
            value = m.value
            group2.remove(m)
            group2.append(MyThread(value))

time.sleep(5.0)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接