Why does WPF Dispatcher.Invoke not deadlock when launched on the main thread?

Consider the code:

public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }

        private void button_Click(object sender, RoutedEventArgs e)
        {
            //System.Threading.Thread.CurrentThread = button.Dispatcher.Thread
            button.Dispatcher.Invoke(() => button.Content = "1234");
        }
    }

      

button_Click

Runs on the main thread , of course .

I understand that it button.Dispatcher.Thread

is the main thread and Invoke()

is only processed when the thread is not blocking. However, in this case, isn't the main thread blocked? That is, the main thread is waiting for the call to complete Dispatcher.Invoke()

, and is Dispatcher.Invoke()

waiting for the main thread to release. Therefore, I am waiting for a dead end here, but it is not dead end.

Why?

PS: I know that in this situation I don't need it Dispatcher.Invoke

and I can directly call button.Content = "1234"

. I'm trying to figure out why no deadlock occurs in this case.

+3


source to share


1 answer


I believe that your misunderstanding may be based on the following thought process:

"Well, Invoke blocks the calling thread until the action is complete. How can it perform an action on the thread if the thread is blocked?"

If we look inside the source, we can see that the callback is not only called on the same thread, but directly * inside the Invoke method. The main thread is not blocked.

If you look at the Reference Source dispatcher page , you can see the following comment above a statement if

in a Invoke

method, with a callable call in it:



// Fast-Path: if on the same thread, and invoking at Send priority,
// and the cancellation token is not already canceled, then just
// call the callback directly.
if(!cancellationToken.IsCancellationRequested && priority == DispatcherPriority.Send && CheckAccess())
{
    /* snipped */

    callback();

    /* snipped */
}

      

You call Dispatcher.Invoke

on the main thread and the method handles this by simply calling it instantly.

* Well, not directly, but the whole element Invoke(Action)

is just a call to the method that contains the above code.

+6


source







All Articles