Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Task.Factory.StartNew and synchronization context

A simple question. Here is a part of a WinForms app:

void Form1_Load(object sender, EventArgs e)
{
    var task2 = Task.Factory.StartNew(() => MessageBox.Show("Task!"),
        CancellationToken.None,
        TaskCreationOptions.None,
        TaskScheduler.FromCurrentSynchronizationContext());

    Debug.WriteLine("Before Exit");
    MessageBox.Show("Exit!");
}

Could someone please explain why I see "Task!" first, and then "Exit" when I run this?

And when I see the "Task!" message box, "Before Exit" has been already printed in the debug output.

EDIT: More simple, same effect:

void Form1_Load(object sender, EventArgs e)
{
    SynchronizationContext.Current.Post((_) => 
        MessageBox.Show("Task!"), null);

    Debug.WriteLine("Before Exit");
    MessageBox.Show("Exit!");
}

EDIT: If I replace MessageBox.Show("Exit!") with Form { Text = "Exit!" }.ShowDialog(), I see "Exit", then "Task", as expected. Why is that?

like image 833
avo Avatar asked Feb 14 '23 17:02

avo


1 Answers

The exact details of Win32 message pumping in the .NET framework are undocumented. Note that the Win32 API has historically permitted reentrant behavior.

When your code starts the task, the task scheduler it's using will request the task to execute on the current SynchronizationContext. So it ends up calling SynchronizationContext.Current.Post, very similar to your second code example.

The WindowsFormsSynchronizationContext works by posting a Win32 message to the message queue; the message type is one defined internally by .NET to mean "execute this code". (These details are undocumented).

When your code proceeds to call MessageBox.Show, it runs a nested message loop, and that is why the queued actions are executing. If you removed the Exit! message box, then the actions would execute after Form1_Load returns to the top-level message loop in Application.Run.

like image 102
Stephen Cleary Avatar answered Feb 16 '23 14:02

Stephen Cleary