0

Async await has different behavior in Win Forms and in my Console App. For the given sample code the output will looks like this:

Line 1: 1
Line 2: 1
Line 3: 1
Line 4: 1
Line 5: 1
Insde the Task: 3
After await: 3

But if I will run similar functions in WinForms on_button_click function I will get this result:

 Line 1: 1
 Line 2: 1
 Line 3: 1
 Line 4: 1
 Line 5: 1
 Insde the Task: 3
 After await: 1 // HERE'S THE DIFFERENCE, after await thread 1 will continue instead of thread 3

That difference in WinForms is significant because thanks to this I will not receive Exception for modifying form outside of dispatcher thread. My question is, how can I achieve same behavior in my console application?

 class Program
{
    public async void methodAsync()
    {
        Trace.WriteLine("Line 2: " + currentThread());
        await method();
        Trace.WriteLine("After await: " + currentThread());
    }
    public Task method()
    {
        Trace.WriteLine("Line 3: " + currentThread());

        Task t = new Task(() =>
        {
            Trace.WriteLine("Insde the Task: " + currentThread());

        });

        t.Start();

        Trace.WriteLine("Line 4: " + currentThread());

        return t;
    }
    public string currentThread()
    {
        return System.Threading.Thread.CurrentThread.ManagedThreadId.ToString();
    }

    public void test()
    {
        Trace.WriteLine("Line 1: " + currentThread());
        methodAsync();
        Trace.WriteLine("Line 5: " + currentThread());

        System.Threading.Thread.Sleep(2000);
    }
    static void Main(string[] args)
    {
        Program p = new Program();
        p.test();
    }
Jurass
  • 435
  • 1
  • 5
  • 17
  • 4
    It is not recommended to define `async void` methods, use the `Task` constructor, or to call `Task.Start`. `async` methods should be awaited. `Thread.Sleep` is definitely a bad idea here. – Aluan Haddad Feb 02 '18 at 00:45
  • 2
    @Gusman first of all it is default, but more importantly console's SynchronizationContext does not have concept or "current/UI" thread to return to and simply continues on whatever thread call comes back – Alexei Levenkov Feb 02 '18 at 00:46
  • @AlexeiLevenkov You are right, my fault. – Gusman Feb 02 '18 at 00:49
  • @Jurass, why do you expect the managed thread id to be the same when you are using the thread pool – johnny 5 Feb 02 '18 at 00:50
  • When using async code, if you await you thread is freed and returned to the thread pool. there is no gaurentee the same thread pick up that task again – johnny 5 Feb 02 '18 at 00:52
  • I'm not sure I understand what the actual problem is. Are you getting an exception on one of those lines? – Rufus L Feb 02 '18 at 00:52
  • @Rufus he's expected the managed thread Id to be the same – johnny 5 Feb 02 '18 at 00:52
  • 1
    Yes, but with that expectation not being met, is there an actual problem? If so, it would be nice to have code that reproduces it. Maybe this is just a "why" question? But OP mentioned *"will not receive Exception for modifying form outside of dispatcher thread"*. I don't see anywhere that would happen... – Rufus L Feb 02 '18 at 00:53
  • @RufusL this looks like it was an assumption made based off of the behavior of the first project – johnny 5 Feb 02 '18 at 00:54
  • @Jurass read this [article](https://blog.stephencleary.com/2013/11/there-is-no-thread.html) on threads to get a better understand of how threads work – johnny 5 Feb 02 '18 at 00:55
  • 2
    To do this, you'd basically need to write your own sync-context for the console – Marc Gravell Feb 02 '18 at 01:03
  • Its probably a duplicate of https://stackoverflow.com/questions/31564204/c-sharp-async-await-strange-behavior-in-console-app , however, this current question has some great links and information by its self – TheGeneral Feb 02 '18 at 01:17
  • @Saruman the question you've linked indeed sounds similar, but deals with somewhat opposite problem - author expected magic from `async` to create threads automatically, but it did not work - so linked question essentially single threaded code and not surprisingly thread ID does not change. – Alexei Levenkov Feb 02 '18 at 06:38

1 Answers1

4

Console's SynchornizationContext does not switch threads to execute code after async method returns thus you see same id for async part of the method and same thread Id for code after await. WinForms, WPF Synchronization Contexts pick particular (UI) thread to execute code after await to avoid running code that would run on UI thread if code is synchronous on some other thread.

In theory you can create your own SynchronizationContext that will post continuations to whatever thread you like. In practice console's code generally has no problem to run on any thread and hence it is not necessary (unlike in UI cases where code accessing UI elements must run on UI thread).

If you decide to create your own some samples can be found by https://www.bing.com/search?q=c%23+custom+console+synchronizationcontext like Looking for an example of a custom SynchronizationContext (Required for unit testing)

Alexei Levenkov
  • 98,904
  • 14
  • 127
  • 179