Search code examples
.nettaskwaitdeadlockui-thread

WinForm Task.Wait : why is it blocking the UI?


I guess this kind of things should not be done in general, but I would like to understand why this code is getting the UI blocked, not returning from the await taskMain:

using System.Diagnostics;

namespace TasksTest
{
    public partial class FormMain : Form
    {
        public FormMain()
        {
            InitializeComponent();
        }

        private void buttonTest1_Click(object sender, EventArgs e)
        {
            try
            {
                DoTest1Async().Wait();
            }
            catch (Exception exc) 
            {
                MessageBox.Show(exc.ToString());
            }
        }

        private static async Task DoTest1Async()
        {
            Task taskMain = Task.Run(() => {
                Debug.WriteLine("Test #1 completed");
            });
            await taskMain;
        }
    }
}

If instead of using Wait() I use await it works perfectly. I would like to know if there is a way of executing DoTest1Async synchronously without UI getting blocked.

------- EDITED ----------

Having understood that calling Wait method blocks the UI thread and doesn't allow the completed task taskMain to return to the UI thread context and resume execution... why this next code alternative does not block UI thread the same way??? I still don't understand why taskMain can return if I launch code in another thread having the UI thread blocked in the thread.Join but it can't return in a simple Wait() instruction. It sounds weird... Perhaps Wait method implementation needs a revision...?

        private void buttonTest1_Click(object sender, EventArgs e)
        {
            Thread thread = new(() =>
            {
                try
                {
                    DoTest1Async().Wait();
                    Debug.WriteLine("Unblocked!!");
                }
                catch (Exception exc)
                {
                    MessageBox.Show(exc.ToString());
                }
            });
            thread.Start();
            thread.Join();
            Debug.WriteLine("Thread Finished!");
        }

Solution

  • but I would like to understand why this code is getting the UI blocked

    Because Task.Wait is a blocking operation:

    Wait is a synchronization method that causes the calling thread to wait until the current task has completed. If the current task has not started execution, the Wait method attempts to remove the task from the scheduler and execute it inline on the current thread. If it is unable to do that, or if the current task has already started execution, it blocks the calling thread until the task completes

    not returning from the await taskMain

    It returns, but the subsequent Wait call blocks the thread.

    If instead of using Wait() I use await it works perfectly.

    If it works - use it, one of the reason of async-await introduction is to use in cases exactly like this.

    I would like to know if there is a way of executing DoTest1Async synchronously without UI getting blocked.

    No. By definition.

    Also please read Don't Block on Async Code by Stephen Cleary. Blocking not only freezes UI thread but can lead to deadlocks (it seems that you are having one).