Click here to Skip to main content
16,015,504 members
Articles / General Programming / Threads

How to Manage Multiple Asynchronous Calls by using Delegates

Rate me:
Please Sign up or sign in to vote.
3.67/5 (8 votes)
9 Aug 2010CPOL2 min read 38.7K   359   27   8
How to Manage Multiple Asynchronous Calls by using Delegates

Introduction

There are tons of ways on making asynchronous calls in .NET, and you should choose which one to use based on different scenarios. The scenario I want to cover here is how to deal with a situation where you need to make multiple asynchronous calls, and wait until all of them are completed in order to move on to the next step.

This is a typical situation in which you need to make multiple database calls, and wait for all the result sets to come back before continuing your process.

The Problem

In this example, you have a method SomeRandomNumber, which takes some time to execute, and will return an integer value. You will have to make 3 asynchronous calls to this method and wait until all of them are completed.

C#
private static int SomeRandomNumber(int waitTime)
{
    Thread.Sleep(waitTime);
    return rnd.Next();
}

One of the most common solutions is to put all asynchronous calls to the ThreadPool, and you will need a loop to check if they are all completed, based on some global bool flag in your instance. First of all, the code is not clean, and this imperative style is hard to control in multiple threading situation. You can't be sure no one else will change your flag!

C#
private int? threadOneResult;
private int? threadTwoResult;
private int? threadThreeResult;

public void AsyncCallsWithThreadPool()
{
    ThreadPool.QueueUserWorkItem(ThreadOne, 1000);
    ThreadPool.QueueUserWorkItem(ThreadTwo, 5000);
    ThreadPool.QueueUserWorkItem(ThreadThree, 10000);

    while (threadOneResult == null ||
        threadTwoResult == null ||
        threadThreeResult == null)
    {
        Thread.Sleep(100);
    }

    // continue
    Console.WriteLine(
        String.Format("Result: {0}\t{1}\t{2}",
        threadOneResult,
        threadTwoResult,
        threadThreeResult));
}

ThreadOne, ThreadTwo, and ThreadThree put back the result to the global int? variables. After all three threads are completed, the above method will get out of the while loop.

C#
private void ThreadOne(object state)
{
    threadOneResult = SomeRandomNumber((int)state);
}

private void ThreadTwo(object state)
{
    threadTwoResult = SomeRandomNumber((int)state);
}

private void ThreadThree(object state)
{
    threadThreeResult = SomeRandomNumber((int)state);
}

The Solution

The methods BeginInvoke and EndInvoke will do all the work for you. BeginInvoke will process your asynchronous call in a new thread. EndInvoke will return the result from that thread. If the thread is not completed when you are calling EndInvoke, it will wait. You don't have to implement your wait loop in the main thread. The status of each asynchronous operation is saved in the IAsyncResult object, so one delegate can handle multiple invokes.

This approach can eliminate all the unnecessary global variables, so your asynchronous logic does not need to rely on the state in this instance. This looks clean. The most important thing is that this keeps your threading structure simple.

C#
public void AsyncCallsInDelegate()
{
    GetNumber deleg = new GetNumber(SomeRandomNumber);

    IAsyncResult rst1 = deleg.BeginInvoke(1000, null, null);
    IAsyncResult rst2 = deleg.BeginInvoke(5000, null, null);
    IAsyncResult rst3 = deleg.BeginInvoke(10000, null, null);

    Console.WriteLine(
        String.Format("Result: {0}\t{1}\t{2}",
        deleg.EndInvoke(rst1),
        deleg.EndInvoke(rst2),
        deleg.EndInvoke(rst3)));
}

Life is getting better in .NET 3.5. You can use the generic delegate Func<int> to save the work of declaring a new delegate:

C#
public void AsyncCallsInGenericDelege()
{
    Func<int> deleg = new Func<int>(SomeRandomNumber);

    IAsyncResult rst1 = deleg.BeginInvoke(1000, null, null);
    IAsyncResult rst2 = deleg.BeginInvoke(5000, null, null);
    IAsyncResult rst3 = deleg.BeginInvoke(10000, null, null);

    Console.WriteLine(
        String.Format("Result: {0}\t{1}\t{2}",
        deleg.EndInvoke(rst1),
        deleg.EndInvoke(rst2),
        deleg.EndInvoke(rst3)));
}

History

  • 8/8/2010 - First release on CodeProject

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Software Developer Fidelity
Hong Kong Hong Kong
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions

 
Questionrofl i seen bull crap but who ever wrote this worthless peice of crap is one dumb sob Pin
Member 121615723-Dec-15 13:05
Member 121615723-Dec-15 13:05 
GeneralSometimes the simplest... Pin
Member 142630218-Aug-10 10:40
Member 142630218-Aug-10 10:40 
GeneralMy Vote of 4... Well it Helped Me Pin
all4gsus17-Aug-10 3:55
all4gsus17-Aug-10 3:55 
GeneralMy vote of 1 Pin
Not Active17-Aug-10 2:22
mentorNot Active17-Aug-10 2:22 
General[My vote of 1] Nothing new Pin
Not Active8-Aug-10 7:31
mentorNot Active8-Aug-10 7:31 
GeneralRe: [My vote of 1] Nothing new Pin
StNickolay10-Aug-10 5:41
StNickolay10-Aug-10 5:41 
GeneralRe: [My vote of 1] Nothing new Pin
Not Active10-Aug-10 6:08
mentorNot Active10-Aug-10 6:08 
GeneralRe: [My vote of 1] Nothing new Pin
DaProgramma16-Aug-10 20:34
DaProgramma16-Aug-10 20:34 
.... which is true for most introductory examples. On CodeProject and other places.

It is also true for most books about MS technologies. So, you don't need any books about .NET, SQL-Server etc. at all, because it's all in MSDN. Right?

Frowning...

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.