views:

596

answers:

2

I have an array of threads. Each of them call the run method continuously. At the end of each run method I want them to pause and wait.

How can I get the threads to execute one at a time, and then continue the loop when all are finished? I need them to ALWAYS execute in order (ie: 1, 2, 3, 4 - 1, 2, 3, 4...)

I'm currently using threading.Event, but the results are inconsistent.

Thanks

UPDATE

Thanks everybody for your answers so far.

I'm writing something similar to Robocode in python. Players program a bot and the bots battle it out until one remains. After each "turn" the bots are "paused" then updated and drawn to the screen. Then they all start a new turn.

Example:

# Bot extends threading.Thread
class DemoBot(Bot):
    def __init__(self):
        super(DemoBot, self).__init__()

    def run(self):
        while True:
            self.moveForward(100)
            self.turnLeft(90)

As you can see, the bot is in an infinite loop. In the moveForward method, the bot would move forward 100px. But in order to update the screen correctly, I have to move once, pause, update, then move again. This is why I need to be able to "pause" a bot once its finished and have the program wait for the others before updating the screen.

Hope that makes a little more sense.

A: 

maybe something like

while True:
  list = []
  for i in xrange(100):
    t = myThread(data[i])
    list.append(t)
    t.start()
  for t in list: t.join()
jspcal
+1  A: 

Your description seems to imply you don't want the threads to execute concurrently, which would bring into question why you're using threading in the first place.

I sense two possible answers as to why you'd want to do this.

The first possibility is that you are trying to prevent your threads from working on some sort of shared resource at the same time. If this is the case, you probably want to use threading.Lock or threading.RLock to lock your critical code section. (the below example is coded for python 2.5+, you will need to use explicit lock acquire/releasing on older pythons)

from __future__ import with_statement # only needed on python 2.5
from threading import Lock
lock = Lock()


def worker1():
    #noncritical code
    with lock:
        pass # critical code in here

def worker2():
    with lock:
        critical_code

This will not enforce any sort of ordering, however. When multiple threads try to acquire a lock, all but one will block (and which one acquires the lock next is not determinate)

The fact that you mention ordering makes me think you instead have some sort of producer-consumer cycle going on. That is, one thread generates some output which the next needs to work with. You can use queue.Queue to provide data between threads and have them wake up to gobble the next bit of data.

from queue import Queue

one_to_two = Queue(maxsize=10)    

def worker1():
    while i_have_some_data_stream:
        data = get_data_from_somewhere()
        modified_data = munge_data_somehow(data)
        one_to_two.put(modified_data) #blocks only if queue is currently full

def worker2():
     while True:
        data = one_to_two.get() # blocks until data available
        # do something with data
        # Optionally, put this newly processed data into the next queue.

Queues are a powerful primitive that let you pass messages between threads and implement bounded producer-consumers. If that is your use case, the queue will be more efficient than trying to manually synchronize your thread's ordering.

Crast
Thanks for the detailed information Crast. Do you have any further comments based on my update? Would you still suggest using Queue?
Gavin
No, it seems like you probably want some sort of locking. It seems like the screen updating portion is your critical code section, and depending on how you want things to work, you will want to lock around the section where you draw the bot movement (like, posssibly in each iteration of the loop, or in moveForward.) It depends. Then, to sync all the threads at the end of each turn, you may want to use a `threading.Condition` which will allow you to have them all wait till the master signals it is time to resume.
Crast