0

I'm just learning about task, and async/await implementation and I'm struggling with a simple code example so I was hoping someone could share some lights as to what is going on.

here's the code:

public async Task<string> DoStuff()
{
    Console.WriteLine("Long running op started");
    var myString = await Task<string>.Run(() =>
    {
        var result = "Test";
        for (int counter = 0; counter < 5000; counter++)
        {
            Console.WriteLine(counter);
        }
        return (result);
    });
    Console.WriteLine(myString);
    return myString;
}

private void button1_Click(object sender, EventArgs e)
{
    DoStuff();

    while (true) {
        Console.WriteLine("Doing Stuff on the Main Thread...................");
        System.Threading.Thread.Sleep(100);
}

So the result of the execution is like this: Long running op started 0 1 2 .... 225 226 Doing Stuff on the Main Thread................... 227 .... etc...

However the code in the DoStuff method that is located after the Task.Run is never reached. And I don't understand why. Of course if I put an await in front of the DoStuff call it works but then the main thread is stuck waiting for execution. This is all for learning purpose only. Thanks

EDIT: as the comments below are saying, it is effectively working when the code is a Main entry program and it was originally in a button click event, this is where the problem occurs actually sorry about the confusion.

Etienne
  • 1,058
  • 11
  • 22
  • 3
    I just ran your example and "Test" is printed. Are you sure this is the code you're running? – Yuval Itzchakov Jun 16 '15 at 08:17
  • 2
    I ran it, and it worked fine; "Test" is printed - are you sure you just didn't blink and miss it in all the other console output? – Marc Gravell Jun 16 '15 at 08:18
  • 1
    Confirming, that "Test" is really returned – Marco Jun 16 '15 at 08:19
  • Also, `Of course if I put an await in front of the DoStuff call it works but then the main thread is stuck waiting for execution.` is misleading - `Main` will simply return, and the application will end immediately on reaching the `await`. It sounds like you're not actually running a console application, unlike what the code sample you posted suggests... – Luaan Jun 16 '15 at 08:22
  • 1
    @Luaan He can't actually `await` in Main anyway. I think he got confused. – Yuval Itzchakov Jun 16 '15 at 08:22
  • agreed: "an entry point cannot be marked with the 'async' modifier" (CS4009) – Marc Gravell Jun 16 '15 at 08:24
  • @MarcGravell Except for [ASP.NET vNext](http://stackoverflow.com/questions/28938582/entry-point-can-be-marked-with-the-async-modifier-on-coreclr) :) – Yuval Itzchakov Jun 16 '15 at 08:31
  • As an aside, `Run` is a static method on `Task`, so there is no reason to call `Task.Run` - `Task.Run` would be better. – Charles Mager Jun 16 '15 at 08:53
  • interesting.. So it was not the exact same code that I was running, the only difference is that the "main" is actually a buttonClick and the app is a simple windows form application. I thought it would behave the same way and produce the same result, I apologize for not testing it. This is making me even more confused, as I confirm the code is not reached within a windows app and putting the code in Main into a button click event. – Etienne Jun 17 '15 at 09:48

2 Answers2

2

The problem is that you're consuming the only available UI thread in your button1_Click(). Presumably, your UI is also frozen indefinitely.

When you use async/await, then execution of the continuation - in your case, the line Console.WriteLine(myString); - will continue in the same synchronization context as the original function was invoked in.

In the case of a console application, the synchronization context is the TPL (Task Parallel Library) thread pool. It has multiple worker threads, so it will use one of them to execute the continuation.

In your GUI application case (WinForms/WPF), the synchronization context is the UI thread. There can be only one UI thread, so when you're occupying that thread with your while(true) loop, nothing else can run - not your continuation, and not other window message, which is why your UI is frozen.

To test this, you can remove the while(true) loop, and see that your UI becomes responsive again, and the continuation will run as expected.

Jonathan
  • 6,939
  • 4
  • 44
  • 61
  • Perfect answer thanks a lot, I didn't know about the importance of the synchronization context. – Etienne Jun 19 '15 at 00:50
0

When you use a timer for tests you become highly dependent on the characteristics and load of the test system.

Try this instead:

static async Task<string> DoStuff()
{
    Console.WriteLine("Long running op started");
    var myString = await Task.Run(() =>
    {
        var result = "Test";
        for (int counter = 0; counter < 5000; counter++)
        {
            Console.WriteLine(counter);
        }
        return (result);
    });
    Console.WriteLine(myString);
    return myString;
}

static void Main(params string[] args)
{
    var task = DoStuff();

    while (!task.IsCompleted)
    {
        Console.WriteLine("Doing Stuff on the Main Thread...................");
    }
}
Paulo Morgado
  • 14,111
  • 3
  • 31
  • 59
  • this code is much better and makes more sense however I still don't know why mine is not working as it should (if you want to review it please see my last comment above) – Etienne Jun 18 '15 at 06:49