gpt4 book ai didi

c# - 为什么即使我尝试从工作人员更改 UI 时同步上下文仍为空,为什么即使我不这样做,工作人员仍在 UI 线程上等待?

转载 作者:太空狗 更新时间:2023-10-29 20:16:15 25 4
gpt4 key购买 nike

我在表单上有一个按钮,单击该按钮我调用 FooAsync 并在其完成时阻止 UI 线程。

下面是代码和我的问题。

using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SynContextIfIDontTouchUIInWorkerThread
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

#pragma warning disable 1998
private async void button1_Click(object sender, EventArgs e)
{
// Nicely prints out the WindowsForms.SynchronizationContext
// because we *are* indeed on the UI thread
this.Text = SynchronizationContext.Current.GetType().Name;
Thread.CurrentThread.Name = "UI Thread";
Debug.Print(Thread.CurrentThread.Name);

var t = FooAsync();

// CompletedSynchronously is false,
// so the other work was indeed run on a worker thread
button1.Text = (t as IAsyncResult).CompletedSynchronously
? "Sync" : "Async";

// block the UI thread
// Code freezes here
var s = t.Result;

button1.Text = s;
}
#pragma warning restore 1998

public async Task<string> FooAsync()
{
return await Task.Run(() =>
{
// Whether or not I touch the UI in this worker
// thread, the current sync context returns null.
// Why is that?
// However, it looks like this thread is posting
// something to the UI thread and since the UI
// thread is also waiting for this guy to complete
// it results in a dead lock. Why is that when
// I am not even touching the UI here. Why
// is this guy assuming that I have to post
// something to message queue to run on the UI thread?
// Could it be that this guy is actually running on
// the UI thread?
var ctx = SynchronizationContext.Current;

Debugger.Break();

// Current thread name evaluates to null
// This clearly means it is a thread pool thread
// Then why is the synchronization context null
// when I uncomment out the line that changes the text
// of button1?
Debug.Print(Thread.CurrentThread.Name);

if (ctx != null)
{
// Post to Windows message queue using the UI thread's sync ctx
// button1.Text = ctx.GetType().Name;
Debugger.Break();
}

return "Hello";
});
}
}
}
  1. 为什么同步上下文在我传递给 FooAsync 中的 Task.Run 的匿名方法中返回 null,即使我尝试设置button1Text 属性?

如果我不从匿名方法中对 UI 执行任何操作,则同步上下文为 null,这是我目前对同步上下文的理解所期望的行为。

  1. 为什么会出现这个死锁?它看起来像是传递给 Task.Run 的匿名方法,即使显然在线程池线程上运行,甚至在不接触 UI 时,即当我注释掉设置 button1< 的行时Text 属性正在尝试将某些内容发布到 Windows 消息泵。那是对的吗?如果是,为什么会这样?

无论如何,发生了什么事?是什么导致了死锁。我知道 UI 线程被阻塞了,但为什么这个其他工作线程试图等待 UI 线程空闲?

最佳答案

Why is the synchronization context returning null in the anonymous method that I pass to Task.Run in FooAsync even when I try to set button1's Text property?

在匿名方法内部,代码在线程池线程中运行。在这种情况下,同步上下文为空是正常的。在正常情况下,当您仅在 UI 线程中运行时,您应该期望 UI 应用程序中的同步上下文是非空的。

如果您尝试在匿名方法中更改 button1.Text 的值,您将得到一个异常,因为只有 UI 线程可以更新 UI。在这种情况下,.NET 不会使用 UI 线程来更新 UI。

Why is there this dead-lock? It looks like the anonymous method passed to Task.Run, even though clearly running on a thread pool thread and even when not touching the UI, i.e. when I comment out the line that set's button1's Text property, trying to post something to the Windows message pump. Is that correct? And if it is, why so?

因为 await Task.Run(() ... 正在 UI 线程上安排延续,并且由于您正在使用 UI 线程同步等待任务(通过 .结果),则出现死锁。换句话说,继续无法进行,因为UI线程正忙于等待任务。

如果您在 FooAsync() 中删除 asyncawait,您将摆脱死锁,因为 UI 线程上没有延续将被尝试。

另一种消除死锁的方法是通过调用 .ConfigureAwait 告诉 Task.Run...await 不要捕获同步上下文(false); 在任务上。

无论如何,我认为您可能没有以正确的方式做事。

你可能应该这样做:

private async void button1_Click(object sender, EventArgs e)
{
var t = FooAsync();

...

var s = await t;

button1.Text = s;
}

public async Task<string> FooAsync()
{
var something = await Task.Run(() => DoCPUIntensiveNonUIStuff());

DoSomeUIWork();

return ...
}

在这种情况下,async/await 魔法将起作用(捕获 SynchronizationContext,然后在继续时使用它),DoSomeUIWork() 方法将使用 UI 线程运行。

看看这个article about async/await .

关于c# - 为什么即使我尝试从工作人员更改 UI 时同步上下文仍为空,为什么即使我不这样做,工作人员仍在 UI 线程上等待?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37635053/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com