【问题标题】:Async ThreadContext ID异步线程上下文 ID
【发布时间】:2014-08-11 01:15:40
【问题描述】:

更新现在不是问题。没有意识到 Dispatcher.Invoke 方法内外返回的 theadID 不同。

据我了解,当使用 async 时,正在等待的任务 T1 将在不同的线程中执行,并且等待后面的代码被包装为任务 T2,其 ContinueWith 为 T1。所以我假设 threadcontextID 在下面的代码中会有所不同。但是下面的代码生成相同的 ThreadContextID。是不是我的理解错了?

另外,为什么我必须在 T1 中使用 Dispatcher,而在 T2 中可以直接更新主 UI? threadContext 开关在 async/await 中如何工作?谢谢。

更新: T1 中的代码正在 VS 调试线程视图的 MainThread 中执行。但是,如果是在主线程中,为什么我不能直接更新 UI?它给了我 CrossThread 异常。

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;
    }

UI 的 xaml 代码

<Grid>
    <StackPanel>
        <Button Click="AsyncTask">Execute now</Button>
        <TextBox Name="OutputDialog" Background="Gray" Foreground="Yellow" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" VerticalContentAlignment="Stretch">
        </TextBox>
    </StackPanel>
</Grid>

【问题讨论】:

  • 您的意思是Thread.CurrentThread.ManagedThreadId 而不是Thread.CurrentContext?线程和上下文之间没有 1:1 的关系(System.Runtime.Remoting.Contexts.Context,这就是 Thread.CurrentContext 返回的内容)。两个不同的线程可以在同一个上下文中执行。更多细节:stackoverflow.com/a/22761023/1768303.
  • @Noseratio 是的,你是对的。我已经更新了代码。但是,使用 T1.ConfigurateAwait(true) 或 T1.ConfigurateAwait(false),它仍然输出相同的 ManagedThreadID。
  • 你是说你的代码的最后一行显示了相同的线程ID?对于您访问ManagedThreadID 的其他两行,它应该是相同的,因为您通过Dispatcher.Invoke 执行它,因此代码在 UI 线程上运行。
  • @Noseratio 你又是对的。 Dispatcher.Invoke 回到主线程。所以它捕获了 MainThread ID。对 Inovke 的调用在工作线程上。
  • async 捕获当前同步上下文并使用它来执行await 表示的延续任务。在 WPF 应用程序中,上下文是 UI 线程,因此 T2 在那里运行。默认情况下,T1 将在线程池线程上运行,因此您需要使用调度程序手动将操作编组到 UI 线程。

标签: c# asynchronous async-await threadcontext


【解决方案1】:

在等待之后,流程被安排在调用线程上,因此您不需要在 T2 中调用 Invoke。如果您想继续 T1 的线程,请使用 .ConfigureAwait(continueOnCapturedContext: false)

【讨论】:

  • 另外,如果我使用await T1.ConfigureAwait(false),我会在直接更新UI时捕获跨线程异常。如果 T1.ConfigurateAwait(true),则不存在这样的问题。在这两种情况下,thead ContextID 再次相同。为什么?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多