-1

I have a problem understanding why the rest of the function after using async is done in different threads for the same code. Take an example - in CODE 1 the rest of the RunClick function is executed in thread 3, which is logical, because the DoAsyncWork function was executed in it.

In the case of CODE 2, the rest of the btnCallMethod_Click function is still executed in thread 1., although the function DoWorkAsync was done in thread 3.

The only difference is that btnCallMethod_Click is called from Windows Forms - it handles Click event for a standard button.

What does it depend on ? Does Windows Forms trigger events in any special way that the thread does not change?

//CODE 1:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace ConsoleApp61
{

    class Test
    {
        public event EventHandler Click;
        public string TestString { get; set; }
        internal void DoClick()
        {
            Click?.Invoke(this, new EventArgs());
        }

        public async void RunClick(object sender, EventArgs e)
        {
            Console.WriteLine("Before async call " + Thread.CurrentThread.ManagedThreadId); // Thread id=1
            (sender as Test).TestString = await DoAsyncWork(1);
            Console.WriteLine("After async call " + Thread.CurrentThread.ManagedThreadId); //Thread id=3 OK
        }

        private Task<string> DoAsyncWork(int step)
        {
            return Task.Run(() => {
                Thread.Sleep(10000);
                Console.WriteLine($"DoAsyncWork() " + Thread.CurrentThread.ManagedThreadId); //Thread id=3
                return "555";
            });
        }
    }

    class Program
    {     
        static async Task Main(string[] args)
        {
            Test x = new Test();
            x.Click += x.RunClick;
            x.DoClick();
            Console.ReadKey();
        }
    }
}

/////////////////////////////////////////////////////////////////////
// CODE 2:
private async void btnCallMethod_Click(object sender, EventArgs e)
        {
            Console.WriteLine("step 1-" + Thread.CurrentThread.ManagedThreadId); //Thread id=1
            this.Text = await DoWorkAsync();
            Console.WriteLine("step 2-" + Thread.CurrentThread.ManagedThreadId); //Thread id=1 Still 1 !!! Why ? Should  be 3
        }

        private async Task<string> DoWorkAsync()
        {
            return await Task.Run(() =>
            {
                Thread.Sleep(10000);
                Console.WriteLine("step 99-" + Thread.CurrentThread.ManagedThreadId); // Thread id =3
                return "Done with work!";
            });
        }
  • 1
    Are you asking why `await` continues in same thread in UI, but in different thread if it's not UI? You can find some insights in [this question](https://stackoverflow.com/q/21390186/1997232). – Sinatr Jul 26 '19 at 11:28
  • 1
    It's never good to use Thread.Sleep() in async code - try replacing this with await Task.Delay() and remove the unnecessary Task.Run() from your DoWorkAsync(), then see if you still get the same results. – Peregrine Jul 26 '19 at 11:29
  • 1
    Yes, the question is: why await continues in the same thread if method is called from UI, and why not if it's called from my private class (event). – John Smith Jul 26 '19 at 11:33
  • Take a look at: https://devblogs.microsoft.com/pfxteam/await-synchronizationcontext-and-console-apps/ it's well explained – polkduran Jul 26 '19 at 13:03
  • I recommend reading my [async intro](https://blog.stephencleary.com/2012/02/async-and-await.html). – Stephen Cleary Jul 26 '19 at 22:12

1 Answers1

0

No, it shouldn't be 3 in the code 2. It's all about synchronization context.

There is no synchronization context in console application, so task continuations are executed on thread pool in code 1.

WPF and WinForms applications have synchronization context to route execution back to UI thread to modify controls for instance.

Try this this.Text = await DoWorkAsync().ConfigureAwait(false); in the 2nd example and your code won't be returned to thread 1.

Also check my answer here Is ConfigureAwait(false) required on all levels of the async chain when no real I/O call is involved?

What Is SynchronizationContext

mtkachenko
  • 5,389
  • 9
  • 38
  • 68