Bob
Bob

Reputation: 1625

How can I get my application to continue, only when all async operations are complete?

In my application, I used to create along string of async operations, which passed in functions like this:

public void LotsOfAsync()
{
    DoAsync1( ()=> { DoAsync2( ()=> { doAsync3( ()=> { finalAction();}) } ) } );
}

However, now I have moved many of those async operations into separate classes and objects but I want the same results. Mainly I have moved those async operations into classes which become part of a collection.

I'd like my new code to look like this:

public void lotsOfAsync()
{
    DoAsync1();
    for each ( MyClass in Async1List)
     { 
          MyClass.DoAsyn2(); 
      }
    if (allAsyncOperationsAreComplete)
    {
        FinalAction();
    }
}

What things do I need to do, to get this to work? Thanks.


Using the Answer below about Tasks, something still seems to be lacking. The program never continues even after throwing everything into a BackgroundWorker.

Upvotes: 3

Views: 842

Answers (5)

BrokenGlass
BrokenGlass

Reputation: 160982

You can use Task<T> (using the Task Parallel Library for Silverlight) - something like this maybe:

List<Task> tasks = new List<Task>();

Task.Factory.StartNew(() => DoAsync1()).ContinueWith(_ =>
{
    foreach (MyClass myClass in Async1List)
    {
        tasks.Add(Task.Factory.StartNew(() => myClass.DoSomething()));
    }
    Task.WaitAll(tasks.ToArray());
    FinalAction();
});

Upvotes: 4

Bob
Bob

Reputation: 1625

After looking through all the previous answers, I was unable to solve my problem.

Instead what I needed to do, was create custom Events within my classes, which triggered upon a successful completion of the asynchronous tasks.

The website that proved the most useful to me to accomplish this was: http://www.marten-online.com/csharp/simple-custom-event-handling.html

My final code looked something like this:

public void lotsOfAsync()
{
    DoAsync1();
    for each ( MyClass in Async1List)
     {    
          MyClass.PropertyChange += new MyClass.PropertyChangeHandler(Async2Complete);
          MyClass.DoAsyn2(); 
      }
 }

 public void Async2Complete(object sender, PropertyChangeEventArgs data)
        {
            if (data.PropertyName == "AsyncComplete")
            {
                totalAsyncCompleted++;
                if (totalAsyncCompleted >= Async1List.Count)
                {
                    FinalAction();
                }
            }
        }

Upvotes: 1

Jeb
Jeb

Reputation: 3799

Have you had a look at the CountdownEvent in .Net 4? This is a signalling construct where one thread will block and only proceed once other threads have completed and called set on the count down event. You initialise it with the number of signals you need before the thread calling Wait on the construct will proceed. E.g.:

 CountdownEvent countdown = new CountdownEvent(3);

will only let the thread calling Wait to proceed once 3 other threads have called Signal.

So your example would perhaps look something like this:

public void lotsOfAsync()      
{
    Int32 numberOfAsyncProcesses = Async1List.Length + 1;         
    CountdownEvent countdown = new CountdownEvent (numberOfAsyncProcesses);

    DoAsync1(countdown); // call countdown.signal() in the async method once complete.

    for each ( MyClass in Async1List)           
    { 
        // call countdown.signal() in the async method once complete.
        MyClass.DoAsyn2(countdown);        
    }   

    if(countDown.Wait(TimeSpan.FromSeconds(3))
    {             
        FinalAction();      
    }
}

I've also added a timeout where the calling thread will unblock after 3 seconds if failed to get a response from all processing threads. In this case, the final action will not be performed.

You can reproduce this with Monitor/Pulse if you are not targeting .Net 4.

There is a nice example here too. Hope this helps!

Upvotes: 1

Tobias
Tobias

Reputation: 883

Have you heard of the Deferred pattern often used in Javascript?

It is simple to work with and very dynamic and you should be able to implement it on Windows phone aswell.

Have a look at this guide http://twistedmatrix.com/documents/current/core/howto/defer.html

Regards Tobias

Upvotes: 0

Lonli-Lokli
Lonli-Lokli

Reputation: 3786

Im not familiar with wp7, but you may use counter as static field and check if it's equal to 0 in final action.

Every MyClass.DoAsyn2() should fire maybe a event, or any other code to signal that it is finished.

Another option is to move all async to task and call Task.WaitAll

http://msdn.microsoft.com/en-us/library/dd270695.aspx

Upvotes: 2

Related Questions