Duncan's method is probably the best and is what I would recommend. I've been mildly annoyed by the lack of "wait for next completed thread to complete" before, though, so I just wrote this up to try it out. Seems to work. Simply use MWThread
in place of threading.thread
and you get this new wait_for_thread
function.
The global variables are a bit klunky; an alternative would be to make them class-level variables. But if this is hidden in a module (mwthread.py or whatever) it should be fine either way.
#! /usr/bin/env python
# Example of how to "wait for" / join whichever threads is/are done,
# in (more or less) the order they're done.
import threading
from collections import deque
_monitored_threads = []
_exited_threads = deque()
_lock = threading.Lock()
_cond = threading.Condition(_lock)
class MWThread(threading.Thread):
"""
multi-wait-able thread, or monitored-wait-able thread
"""
def run(self):
tid = threading.current_thread()
try:
with _lock:
_monitored_threads.append(tid)
super(MWThread, self).run()
finally:
with _lock:
_monitored_threads.remove(tid)
_exited_threads.append(tid)
_cond.notifyAll()
def wait_for_thread(timeout=None):
"""
Wait for some thread(s) to have finished, with optional
timeout. Return the first finished thread instance (which
is removed from the finished-threads queue).
If there are no unfinished threads this returns None
without waiting.
"""
with _cond:
if not _exited_threads and _monitored_threads:
_cond.wait(timeout)
if _exited_threads:
result = _exited_threads.popleft()
else:
result = None
return result
def main():
print 'testing this stuff'
def func(i):
import time, random
sleeptime = (random.random() * 2) + 1
print 'thread', i, 'starting - sleep for', sleeptime
time.sleep(sleeptime)
print 'thread', i, 'finished'
threads = [MWThread(target=func, args=(i,)) for i in range(3)]
for th in threads:
th.start()
i = 0
while i < 3:
print 'main: wait up to .5 sec'
th = wait_for_thread(.5)
if th:
print 'main: got', th
th.join()
i += 1
else:
print 'main: timeout'
print 'I think I collected them all'
print 'result of wait_for_thread():'
print wait_for_thread()
if __name__ == '__main__':
main()