mmx_scamper

I have a scenario wherin i have to ping two servers inside a method and get back the results.The results is passed to the caller once both the server call returns.For this I'm using an Asyncdelegate/waithandle combination.A sample of the code is mentioned below.

Code Block
using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace WaitHandleConsoleSample
{
public delegate object WorkerDelegate();

class Program
{
static void Main(string[] args)
{
int i = 3;
int x = 7;
WorkerDelegate firstThread = delegate()
{
return Iterator1();
};

WorkerDelegate secondThread = delegate()
{
return Iterator2();
};

IAsyncResult thread1Result = firstThread.BeginInvoke(null, null);

IAsyncResult thread2Result = secondThread.BeginInvoke(null, null);

System.Diagnostics.Debug.WriteLine("WAITING BEGUN IN MAIN THREAD");

WaitHandle.WaitAll(new WaitHandle[] { thread1Result.AsyncWaitHandle, thread2Result.AsyncWaitHandle });

System.Diagnostics.Debug.WriteLine("WAITING ENDED IN MAIN THREAD");

object result1 = firstThread.EndInvoke(thread1Result);


object result2 = secondThread.EndInvoke(thread2Result);

System.Diagnostics.Debug.WriteLine("THREAD 1 Result:" + result1.ToString());

System.Diagnostics.Debug.WriteLine("THREAD 2 Result:" + result2.ToString());

Console.Read();

}

static object Iterator1()
{
int i;
for (i = 0; i < 10000; i++)
{
System.Diagnostics.Debug.WriteLine("Thread 1 Value:" + i);
}

return i;
}

static object Iterator2()
{
int i;
for (i = 0; i < 10002; i++)
{
System.Diagnostics.Debug.WriteLine("Thread 2 Value:" + i);
}
return i;
}
}
}


After going through MSDN i found that the same can be achieved using BeginInvoke/EndInvoke combination. i.e EndInvoke waits till the operation returns as in the sample below...

Code Block

using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;

namespace WaitHandleConsoleSample
{
public delegate object WorkerDelegate();

class Program
{
static void Main(string[] args)
{
int i = 3;
int x = 7;
WorkerDelegate firstThread = delegate()
{
return Iterator1();
};

WorkerDelegate secondThread = delegate()
{
return Iterator2();
};

IAsyncResult thread1Result = firstThread.BeginInvoke(null, null);

IAsyncResult thread2Result = secondThread.BeginInvoke(null, null);

System.Diagnostics.Debug.WriteLine("WAITING BEGUN IN MAIN THREAD");


object result1 = firstThread.EndInvoke(thread1Result);

System.Diagnostics.Debug.WriteLine("WAITING ENDED IN THREAD 1");

object result2 = secondThread.EndInvoke(thread2Result);

System.Diagnostics.Debug.WriteLine("WAITING ENDED IN THREAD 2");

System.Diagnostics.Debug.WriteLine("THREAD 1 Result:" + result1.ToString());

System.Diagnostics.Debug.WriteLine("THREAD 2 Result:" + result2.ToString());

Console.Read();

}

static object Iterator1()
{
int i;
for (i = 0; i < 10000; i++)
{
System.Diagnostics.Debug.WriteLine("Thread 1 Value:" + i);
}

return i;
}

static object Iterator2()
{
int i;
for (i = 0; i < 10002; i++)
{
System.Diagnostics.Debug.WriteLine("Thread 2 Value:" + i);
}
return i;
}
}
}

My question is which one is the best way to wait for an Async operation/operations to return... Using delegate beginInvoke/WaitHandle/EndInvoke pattern or delegate BeginInvoke/Endinvoke pattern...

Both yields the same results,both waits until both the operations are completed...So,what really is the difference in both

Is this the best way to do this kind of an operation,or do you suggest any better ways...

Thanks in advance for any suggestions,
Mmx


Re: Visual C# General How to join two AsyncDelegates; using AsyncwaitHandle or EndInvoke??

Peter Ritchie

The calls to EndInvoke perform the same wait on the wait handle that you performed; so they're essentially identical.

If you want a timeout on the wait you'll need to perform the wait manually. Keep in mind, WaitAll can only be performed on an MTA thread (e.g. not the GUI thread). So, it's best to use a couple of EndInvokes if you're doing this on a GUI thread. This is a classic fork/join pattern, where one thread forks (spawns) one or more new threads and joins (waits) for them to completed before continuing.






Re: Visual C# General How to join two AsyncDelegates; using AsyncwaitHandle or EndInvoke??

mmx_scamper

>>WaitAll can only be performed on an MTA thread (e.g. not the GUI thread). So, it's best to use a couple of EndInvokes if you're doing this on a GUI thread.

Can i perform the below mentioned operation in a button handler (i.e a GUI/STA thread)


Code Block
WorkerDelegate firstThread = delegate()
{
return Iterator1();
};
WorkerDelegate secondThread = delegate()
{
return Iterator2();
};
IAsyncResult thread1Result = firstThread.BeginInvoke(null, null);
IAsyncResult thread2Result = secondThread.BeginInvoke(null, null);
WaitHandle.WaitAll(new WaitHandle[] { thread1Result.AsyncWaitHandle, thread2Result.AsyncWaitHandle });
object result1 = firstThread.EndInvoke(thread1Result);
object result2 = secondThread.EndInvoke(thread2Result);

I just tried putting the code in button handler and it seems to be working What is the potential pitfall involved in writing the above mentioned piece of code in a GUI thread

My idea was that the GUI thread on seeing the WaitAll construct would wait till it gets signalled..is it a wrong impression

Can you direct me to some resources were i can get a more elaborate explanation

Thanks,

Mmx





Re: Visual C# General How to join two AsyncDelegates; using AsyncwaitHandle or EndInvoke??

Peter Ritchie

You can't call WaitAll from an STA thread because WaitAll doesn't pump messages while it blocks your thread. An STA Thread is required to pump messages at a reasonably responsive frequency.

Apart from being an STA thread, you should not block the GUI thread for an indeterminate amount of time because you make your application unresponsive and it will appear to be hung. Users don't have patience for that and will generally terminate your application via Task Manager if it's unresponsive for very long (like more than a couple of seconds).






Re: Visual C# General How to join two AsyncDelegates; using AsyncwaitHandle or EndInvoke??

mmx_scamper

Thanks and point understood...

Does endinvoke exhibit the same issue as WaitAll... i.e does waiting on EndInvoke inside a GUI thread makes the application unresponsive to user events

Thanks,

Mmx





Re: Visual C# General How to join two AsyncDelegates; using AsyncwaitHandle or EndInvoke??

Peter Ritchie

Yes and no. EndInvoke essentially calls WaitOne which keeps the thread's message pump pumping messages which fulfills your STA obligations. But, it doesn't do anything to keep your GUI responsive so it's not a good idea to call EndInvoke on your GUI thread. Sometimes it's alright to call WaitOne because you can specify a timeout so you don't have to block your GUI for an indeterminate amount of time; but EndInvoke doesn't have a timeout, it simply blocks until whatever was invoked completes.

When you're dealing with asynchronous code with a UI, the easiest method of ensuring your UI is responsive is to use the Asynchronous Programming Model (APM) which uses Completed events to signal an observer that the task has completed. When dealing with a UI the BackgroundWorker class provides an easy method of implementing the APM that allows you to easily ensure you're UI is responsive.