1

Why don't I see anything in the console when I run the program below?

Screenshot for proof.

I see both done-messages when I uncomment both lines (why not only "Foo Done!"?)

class Program
{
    static void Main(string[] args)
    {
        //var foo = new Foo();
        var bar = new Bar();
    }

    private class Foo
    {
        public Foo()
        {
            DoWork();
        }

        private void DoWork()
        {
            Console.WriteLine("Foo Done!");
        }
    }

    private class Bar
    {
        public Bar()
        {
            DoWorkAsync();
        }

        private async void DoWorkAsync()
        {
            await Task.Run(() => Console.WriteLine("Bar Done!"));
        }
    }
}
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
Szer
  • 3,426
  • 3
  • 16
  • 36
  • 2
    @EugenePodskal The code has a race condition; it's result is not deterministic. – Servy May 12 '15 at 16:30
  • @EugenePodskal [proof](http://imgur.com/uy2zCQt) – Szer May 12 '15 at 16:33
  • @Servy race condition perfectly explains first part of the question. And I really see `"Bar Done!"` in some cases. But why in the second case I always see both messages? Isn't it the same race condition? – Szer May 12 '15 at 16:37
  • Just because you happen to see it doesn't mean that there isn't a race condition, it just means the race condition happened to result in a different action. Such is the nature of race conditions. – Servy May 12 '15 at 16:40

4 Answers4

1

Easy as this:

Just add

Console.ReadLine(); // waits for a key to be pressed on form

after calling

var bar = new Bar();

to wait for a user action.

cramopy
  • 3,459
  • 6
  • 28
  • 42
  • But why I see both messages when I uncomment both lines? Why not only `"Foo done!"` ? – Szer May 12 '15 at 16:28
1

As it has been pointed by @Servy it is a non-deterministic behaviour - I was unable to get it not printed on my machine, you were unable to get it printed on yours.

Why is it non-deteministic? Because:

  1. Tasks are created as background threads
  2. Console has no synchronization context

That means that both the task you run and its continuation (registered through async awaiter) will be run on a background thread, so if the main thread(whole application) ends before it is able to print, you won't see anything.

Why does it print for you in the second case? Again - because it is a non-deterministic behaviour depending on task scheduling and operating system state.

Community
  • 1
  • 1
Eugene Podskal
  • 10,270
  • 5
  • 31
  • 53
1

But why I see both messages when I uncomment both lines? Why not only "Foo done!" ?

Your code has a race condition between the termination of Main and the execution of the delegate on a threadpool thread, hence your results will be non deterministic. If the Task executes the delegate fast enough, you'll see both. There is no guarantee one will finish before the other.

Run your code enough times and you'll probably catch only "Foo Done" eventually.

Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321
1

You are probably seeing "Bar Done!" by luck when you have both uncommented.

Because you are running Bar async the main thread probably finishes before it has had chance to write to the console. Adding Foo in probably slows the main thread enough for the write to work.

Try awaiting DoWorkAsync

private class Bar { 
    public Bar() { 
        DoWorkAsync().Wait(); 
    } 

    private async Task DoWorkAsync()
   { 
       return await Task.Run(() => Console.WriteLine("Bar Done!")); 
   } 
}
Mike Norgate
  • 2,393
  • 3
  • 24
  • 45
  • 1
    `return` keyword is unnecessary here and produces compile error. But your solution force program work like intended. Thank you – Szer May 12 '15 at 16:52