【发布时间】:2020-05-21 04:21:27
【问题描述】:
我在 UI 线程上的 WPF 中使用异步等待。我有一个关于 async await 在特定情况下如何工作的问题。我将尝试通过一个例子来解释它。
背景
假设我有带有单击事件处理程序ButtonA_Click() 的按钮A 和带有ButtonB_Click() 的按钮B。点击处理程序将检查RunLoop() 方法是否仍在运行。如果它没有运行,它们会启动RunLoop()。
问题:
- 当(外部)
await RunLoop()被调用时,事件处理程序是否会从 UI 线程返回? - 或者它会在
RunLoop()的(内部)等待处返回,因为它可以在Runloop()的开头执行同步代码(_isStopped = false;)。
如果 1. 为真,它可能会导致赛车状况,或者?当同时调用两个点击处理程序时,它们将在 UI-Thread 上紧接着运行。因此,第二个事件处理程序可能会在第一次执行 RunLoop() 之前运行。在这种情况下,_isStopped 对于第二个事件处理程序仍然是错误的,它也会启动一个RunLoop()。因此 2 RunLoop() 将处于活动状态。对吗?
(PS:我知道,如果 1. 是这种情况,我可以通过将_isStopped = false 放入点击处理程序来解决这个问题,但这个问题更多的是关于了解当方法嵌套时异步等待如何工作) .
代码
private bool _isStopped = true;
private List<Customer> _customers; // will be filled from somewhere else
public async void ButtonA_Click()
{
// do some stuff synchronously
if (_isStopped)
await RunLoop();
}
public async void ButtonB_Click()
{
// do some stuff synchronously
if (_isStopped)
await RunLoop();
}
private async Task RunLoop()
{
_isStopped = false;
while (_customers.Any())
{
_customers.Remove(...);
await Task.Run(() => ProcessStuff());
}
_isStopped = true;
}
得到答案后更新:
这些链接帮助我更好地理解它
【问题讨论】:
-
你知道
List<Customer> _customers不是线程安全的,它是由多个线程并发访问而不同步的吗? -
@TheodorZoulias 好点。它可以被2个线程访问。这是我遇到的问题的简化版本。我发现我在创建这个版本时犯了一个错误。客户实际上在 Task.Run() 上方的 while 循环中被删除,而不是在 ProcessStuff() 中。但这并没有改变真正的问题。
-
我打算这么建议。只要您仅从 UI 线程访问和操作
List,就不会出现任何线程安全问题。 :-)
标签: c# wpf async-await