views:

666

answers:

5

I have run into this problem across multiple programming languages and I was just wondering what the best way to handle it is.

I have three method calls that fire off asynchronously. Each one has a callback. I want to do something only when all three callbacks have completed.

What is the best way to code this? I usually end up with all these public bool flags and as you add more calls the code gets more convoluted.

+1  A: 

If you really only want to wait for all to finish:

  1. Create volatile counter
  2. Synchronize access to counter
  3. Increase counter on start
  4. Decrease on callback fired
  5. Wait for counter to reach 0
jitter
A: 

Use a semaphore.

patros
+3  A: 

Coming from C#, I would probably use WaitHandle.WaitAll. You can create an array of ManualResetEvent objects (one for each task to be completed), and pass that array to WaitAll. The threaded tasks will get one ManualResetEvent object each, and call the Set method when they are ready. WaitAll will block the calling thread until all tasks are done. I'll give a C# code example:

private void SpawnWorkers()
{
    ManualResetEvent[] resetEvents = new[] {
            new ManualResetEvent(false), 
            new ManualResetEvent(false)
        };

    // spawn the workers from a separate thread, so that
    // the WaitAll call does not block the main thread
    ThreadPool.QueueUserWorkItem((state) =>
    {
        ThreadPool.QueueUserWorkItem(Worker1, resetEvents[0]);
        ThreadPool.QueueUserWorkItem(Worker2, resetEvents[1]);
        WaitHandle.WaitAll(resetEvents);
        this.BeginInvoke(new Action(AllTasksAreDone));

    });
}
private void AllTasksAreDone()
{
    // OK, all are done, act accordingly
}

private void Worker1(object state)
{
    // do work, and then signal the waiting thread
    ((ManualResetEvent) state).Set();
}

private void Worker2(object state)
{
    // do work, and then signal the waiting thread
    ((ManualResetEvent)state).Set();
}

Note that the AllTasksAreDone method will execute on the thread pool thread that was used to spawn the workers, and not on the main thread... I assume that many other languages have similar constructs.

Fredrik Mörk
What context are we in when calling this.BeginInvoke? What is 'this'?
steve_c
A: 
Hans Malherbe
some of the classes are missing from this example
mcintyre321
A: 

For those using JavaScript, consider using the pattern discussed at this Stackoverflow question: http://stackoverflow.com/questions/2911822/javascript-execute-a-bunch-of-asynchronous-method-with-one-callback

Scott Mitchell