0

UPDATE Not a Problem now. Didn't realize the theadID returned inside and outside the Dispatcher.Invoke method are different.

From my understanding, when using async, the awaiting task T1 will be executed in a different thread and the code following the await are wrapped as task T2 with a ContinueWith of T1. So I assume the threadcontextID would be different in the code below. However the code below generate the same ThreadContextID. Is my understanding wrong?

Also, why I have to use Dispatcher in T1, but can update the main UI in T2 directly? How does the threadContext switch work in async/await? Thanks.

UPDATE: The code in T1 is executing in the MainThread in the VS Debug Thread view. However, if it is in the Main thread, why I can't update the UI directly? It gives me the CrossThread exception.

async private void AsyncTask(object sender, RoutedEventArgs e)
    {
        OutputDialog.Text = Thread.CurrentThread.ManagedThreadId+ Environment.NewLine + OutputDialog.Text;

        Task T1 = new Task(
                    () => {
                            Thread.Sleep(5000);
                            OutputDialog.Dispatcher.Invoke(() => { 
                                OutputDialog.Text = "Task in AWAIT" + Environment.NewLine + OutputDialog.Text;
                                OutputDialog.Text = Thread.CurrentThread.ManagedThreadId + Environment.NewLine + OutputDialog.Text;
                            });
                    });

        T1.Start();

        await T1;

        //T2
        OutputDialog.Dispatcher.Invoke(() => { OutputDialog.Text = "Continued Task after AWAIT 1" + Environment.NewLine + OutputDialog.Text; });

        OutputDialog.Text = "Continued Task after AWAIT 2" + Environment.NewLine + OutputDialog.Text;

        OutputDialog.Text = Thread.CurrentThread.ManagedThreadId + Environment.NewLine + OutputDialog.Text;
    }

xaml code for the UI

<Grid>
    <StackPanel>
        <Button Click="AsyncTask">Execute now</Button>
        <TextBox Name="OutputDialog" Background="Gray" Foreground="Yellow" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch">
        </TextBox>
    </StackPanel>
</Grid>
Helic
  • 907
  • 1
  • 10
  • 25
  • Did you mean `Thread.CurrentThread.ManagedThreadId` rather than `Thread.CurrentContext`? There is no 1:1 relationship between thread and context ([`System.Runtime.Remoting.Contexts.Context`](http://msdn.microsoft.com/en-us/library/system.runtime.remoting.contexts.context%28v=vs.110%29.aspx), that's what `Thread.CurrentContext` returns). Two different thread can be executing on the same context. Some more details: http://stackoverflow.com/a/22761023/1768303. – noseratio Jun 20 '14 at 11:40
  • @Noseratio yes you are right. I have updated the code. However, with T1.ConfigurateAwait(true) or T1.ConfigurateAwait(false), it still outputs the same ManagedThreadID. – Helic Jun 20 '14 at 11:48
  • Are you saying that the last line of your code shows the same thread id? For the other two lines where you access `ManagedThreadID`, it's expected to be the same, as you do it via `Dispatcher.Invoke`, so the code runs on the UI thread. – noseratio Jun 20 '14 at 11:55
  • 1
    @Noseratio you are right again. Dispatcher.Invoke goes back to the Main thread. So it capture the MainThread ID. The call to the Inovke is on a worker thread. – Helic Jun 20 '14 at 12:06
  • `async` captures the current synchronisation context and uses it to execute the continuation task represented by `await`. In WPF applications the context is the UI thread, so `T2` runs there. By default, `T1` will be run on a thread pool thread so you need to manually marshal the action to the UI thread using the dispatcher. – Lee Jun 20 '14 at 12:18

1 Answers1

0

After the await, the flow is scheduled on the calling thread so that is why you don't need the Invoke in T2. If you want to continue on T1's thread then use .ConfigureAwait(continueOnCapturedContext: false)

Emile
  • 2,200
  • 27
  • 36
  • Also, If I use await T1.ConfigureAwait(false), I will capture the crossthread exception when updating the UI directly. If T1.ConfigurateAwait(true), there is no such problem. In both cases, the thead ContextID is again the same. Why? – Helic Jun 20 '14 at 11:05