Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Asynchronous Programming and await in a loop

I started to learn Asynchronous programming in C# 5 and .Net 4.5 and there is something I don't understand.

private static int count;

public static void Main()
{
    LoopTest();

    Console.ReadKey(false);
}

static async void LoopTest()
{
    count = 0;

    for (var index = 0; index < 10; ++index)
    {
        Console.WriteLine( "({0}) In Loop before await, Index {1}, Thread: {2}", count++, index, Thread.CurrentThread.ManagedThreadId);
        await Task.Factory.StartNew(() => Thread.Sleep(10));
    }
}

The result is:

 (0) In Loop before await, Index 0, Thread: 9  
 (1) In Loop before await, Index 1, Thread: 10    
 (2) In Loop before await, Index 2, Thread: 11   
 (3) In Loop before await, Index 3, Thread: 10  
 (4) In Loop before await, Index 4, Thread: 11  
 (5) In Loop before await, Index 5, Thread: 10  
 (6) In Loop before await, Index 6, Thread: 12  
 (7) In Loop before await, Index 7, Thread: 11  
 (8) In Loop before await, Index 8, Thread: 10  
 (9) In Loop before await, Index 9, Thread: 12

So are there different Threads accessing the same loop? is there a Race-Condition on the index variable?

like image 325
m1o2 Avatar asked Jan 17 '13 14:01

m1o2


2 Answers

No, there is no race condition. You start a new task, that will run in the background, but your code will not continue until that task finishes, so you can be sure that your code will only be executed in one thread at any one time.

However, because this is a console application there is no current SyncronizationContext. (As opposed to a winform, WPF, ASP, Silverlight, etc. application in which there will be.) This means that the continuations from any await call will run in the thread pool, not in the calling thread. So yes, you're running in one of the thread pool threads in each iteration of the loop, and it could be a different one each time, but you can be sure that, excepting whatever you put inside the new task, you will "finish" running on any given thread before you start working on the next, which ensures that there is only ever one thread running code at any given time (which means no race conditions).

like image 66
Servy Avatar answered Sep 19 '22 03:09

Servy


What you're doing isn't really asycnhronous

await Task.Factory.StartNew(() => Thread.Sleep(10));

This creates a task and then waits for that task to complete. You may as well just call Thread.Sleep(10) here.

A more appropriate way to do this would be:

Task myTask = Task.Factory.StartNew(() => Thread.Sleep(10));
... do stuff here ...
await myTask; // Now wait for the task to complete

If you want to do a number of tasks in a loop, you should look at the Parallel.Foreach() method.

like image 31
Pete Avatar answered Sep 23 '22 03:09

Pete