可以暂停和恢复的线程?

19

我想创建一个线程,在后台执行某些任务。当需要时,我需要能够有效地“暂停”它,并在稍后“恢复”它。此外,如果线程在执行某些任务时被“暂停”,则应该使调用线程等待直到完成。

我在Python中的多线程编程方面比较新手,所以我还没有深入了解。

基本上我已经实现了所有功能,除了当我的线程正在执行某些任务时,调用线程不能等待暂停被调用。

这是我在代码中尝试实现的大纲:

import threading, time

class Me(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        #flag to pause thread
        self.paused = False

    def run(self):
        while True:
            if not self.paused:
                #thread should do the thing if
                #not paused
                print 'do the thing'
                time.sleep(5)

    def pause(self):
        self.paused = True
        #this is should make the calling thread wait if pause() is
        #called while the thread is 'doing the thing', until it is
        #finished 'doing the thing'

    #should just resume the thread
    def resume(self):
        self.paused = False

我认为我基本上需要一个锁机制,但是在同一线程内?

2个回答

14
< p > 条件对象可以用于此操作。

以下是填充您骨架的示例:

class Me(threading.Thread):
    def __init__(self):
        threading.Thread.__init__(self)
        #flag to pause thread
        self.paused = False
        # Explicitly using Lock over RLock since the use of self.paused
        # break reentrancy anyway, and I believe using Lock could allow
        # one thread to pause the worker, while another resumes; haven't
        # checked if Condition imposes additional limitations that would 
        # prevent that. In Python 2, use of Lock instead of RLock also
        # boosts performance.
        self.pause_cond = threading.Condition(threading.Lock())

    def run(self):
        while True:
            with self.pause_cond:
                while self.paused:
                    self.pause_cond.wait()

                #thread should do the thing if
                #not paused
                print 'do the thing'
            time.sleep(5)

    def pause(self):
        self.paused = True
        # If in sleep, we acquire immediately, otherwise we wait for thread
        # to release condition. In race, worker will still see self.paused
        # and begin waiting until it's set back to False
        self.pause_cond.acquire()

    #should just resume the thread
    def resume(self):
        self.paused = False
        # Notify so thread will wake after lock released
        self.pause_cond.notify()
        # Now release the lock
        self.pause_cond.release()

希望这有所帮助。

很遗憾,恢复功能似乎无法正常工作。没有通知线程吗?所以线程正在通知自己,这并没有做任何事情?也许我的理解是错误的? :) - mickzer
@mickzer:你不会在执行工作的同一个线程中调用pauseresume函数;如果线程正在阻塞等待条件,则没有其他任何操作。线程的run函数是实际运行在指定线程中的唯一函数,另一个线程会暂停(等待工作线程真正处于空闲状态),并在稍后的某个时间点恢复执行。 - ShadowRanger
我的错,self.pause_cond.release() 这一行被 stackoverflow 遮住了 - <pre> 元素没有滚动。我很抱歉 - 答案太棒了。 - mickzer
以下是由mguijarr提供的回答,使用事件而非条件更适合该目的。 - rsjethani
@BobEbert:按照现有的写法,它有点棘手;如果有多个线程被阻塞,只有一个会被resume释放。但如果它没有暂停,所有线程都会打印,直到它被暂停。切换到notify_all会让它们全部同时唤醒(这可能是最好的一致性)。如果你想让只有一个线程做某件事情,你需要采用不同的设计。 - ShadowRanger
显示剩余3条评论

10

使用threading.Event代替布尔变量,并添加另一个用于忙状态的事件:

def __init__(self):
    ...
    self.can_run = threading.Event()
    self.thing_done = threading.Event()
    self.thing_done.set()
    self.can_run.set()    

def run(self):
    while True:
        self.can_run.wait()
        try:
            self.thing_done.clear()
            print 'do the thing'
        finally:
            self.thing_done.set()

def pause(self):
    self.can_run.clear()
    self.thing_done.wait()

def resume(self):
    self.can_run.set()

编辑:之前的回答是错误的,我已经修改并更改了变量名称以使其更清晰。


如果我需要在 print('do the thing') 后暂停,以便其他线程启动,然后恢复此线程,该怎么办? - BAKYAC

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