I'm trying to create a thread, that does stuff in the background. I need to be able to effectively 'pause' it when I need to and 'resume' it again later. Also, if the thread is in the middle of doing something when I 'pause' it, it should make the calling thread wait until it finishes what it's doing.
I'm pretty new to Multithreading in Python, so I haven't gotten all that far.
What I have pretty much does everything except make the calling thread wait if pause is called while my thread is doing something.
Here's the outline of what I'm trying to achieve in code:
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
I think I basically need a locking mechanism, but within the same thread?
Condition
s can be used for this.
Here's an example filling in your skeleton:
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()
Hope that helps.
Use threading.Event
instead of a boolean variable, and add another event for busy state:
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()
edit: previous answer was wrong, I fixed it and changed variable names to be clear
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With