0

I have BeginInvoke a delegate which internally invokes multiple asynchronous operations and i want to wait for all internal operations to complete before callback for main asynchronous operation executes.

I could have easily achieved that using async, await or TPL but can't since my target platform is .Net3.5. Sample code demonstrating my problem -

class Program { static List<string> abc = new List<string>(); static void Main(string[] args) { new Action(() => { A(); }).BeginInvoke(MainCallback, null); } static void MainCallback(IAsyncResult result) { foreach (string str in abc) { Console.WriteLine(String.Format("Main Callback {0}",str)); } } static void A() { for (int i = 0; i < 10; i++) { new Action(() => { Thread.Sleep(1000); }).BeginInvoke(Callback, i); } } static void Callback(IAsyncResult result) { abc.Add(result.AsyncState.ToString()); } } 

I want the output to be something like this -

Main Callback 0 Main Callback 1 Main Callback 2 Main Callback 3 Main Callback 4 Main Callback 5 Main Callback 6 Main Callback 7 Main Callback 8 Main Callback 9 
2
  • stackoverflow.com/q/2987439/34397 Commented Aug 8, 2013 at 19:29
  • @SLaks - Will look that. But can you please let me know if it's possible without TPL? Commented Aug 8, 2013 at 19:33

2 Answers 2

4

You need to track how many operations you've started.

Then, in each callback, decrement this counter (to indicate that one of the operations is finished).

When it reaches 0, everything is finished, so you can call the final callback.

This is how Task.WhenAll() works.

Since this is a multi-threaded environment, you must use Interlocked.Decrement (carefully).

Sign up to request clarification or add additional context in comments.

6 Comments

Thanks. You mentioned carefully. Is this good enough - Interlocked.Decrement(ref counter); abc.Add(result.AsyncState.ToString()); if (counter == 0) MainCallback(null); or i need to do something more?
@RohitVats: No; counter may change between those two lines. You need to check the return value of Decrement().
counter = Interlocked.Decrement(ref counter); - is this what you meant? And do i need to wrap entire code in lock?
@RohitVats: No; that's even worse. If a different thread decrements it at the same time, its changes will be swallowed. YOu need to check whether the return value is 0.
You can use Interlocked to write lock-free thread-safe code. However, you need to learn more about thread-safety. See also my blog post, blog.slaks.net/2013-07-22/thread-safe-data-structures
|
-1

You could achieve expected output by modifying little of your code. Modify your A method as below. You're done

static void A() { List<IAsyncResult> results = new List<IAsyncResult>(); for (int i = 0; i < 10; i++) { results.Add(new Action(() => { Thread.Sleep(1000); }).BeginInvoke(Callback, i)); } foreach (var res in results) { res.AsyncWaitHandle.WaitOne(); } } 

Does this helps?

9 Comments

I think he wants to wait asynchronously.
@SLaks What do you mean by wait asynchronously? as you can see Here ThreadPool Thread only waits for operations to complete not the main Thread. OP stated that i want to wait for all internal operations to complete before callback for main asynchronous operation executes This code does what he wants. If am wrong correct me!
Your foreach loop is blocking. He just wants to call the callback later.
-1 for sleeping in a multithreaded asynchronous environment. This answer is not useful.
@SriramSakthivel: The point is that it's a blocking call, which defeats the purpose of asynchrony.
|

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.