Den*_*orz 4 c# multithreading asynchronous task-parallel-library async-await
有时我会遇到访问对象字段的异步/等待代码。例如,无状态项目中的这段代码:
private readonly Queue<QueuedTrigger> _eventQueue = new Queue<QueuedTrigger>();
private bool _firing;
async Task InternalFireQueuedAsync(TTrigger trigger, params object[] args)
{
if (_firing)
{
_eventQueue.Enqueue(new QueuedTrigger { Trigger = trigger, Args = args });
return;
}
try
{
_firing = true;
await InternalFireOneAsync(trigger, args).ConfigureAwait(false);
while (_eventQueue.Count != 0)
{
var queuedEvent = _eventQueue.Dequeue();
await InternalFireOneAsync(queuedEvent.Trigger, queuedEvent.Args).ConfigureAwait(false);
}
}
finally
{
_firing = false;
}
}
Run Code Online (Sandbox Code Playgroud)
如果我理解正确,则await **.ConfigureAwait(false)表明在此之后执行的代码await不一定必须在相同的上下文中执行。所以while这里的循环可以在 ThreadPool 线程上执行。我不明白是什么确保_firing和_eventQueue字段同步,例如什么在这里创建锁/内存栅栏/屏障?所以我的问题是;我是否需要使字段线程安全,或者 async/await 结构中是否有某些内容负责处理此问题?
编辑:澄清我的问题;在这种情况下InternalFireQueuedAsync,应始终在同一线程上调用。在这种情况下,只有延续可以在不同的线程上运行,这让我想知道,我是否需要同步机制(如显式屏障)来确保值同步以避免此处描述的问题:http://www. albahari.com/threading/part4.aspx
编辑2:无状态也有一个小讨论: https://github.com/dotnet-state-machine/stateless/issues/294
我不明白是什么确保 _firing 和 _eventQueue 字段同步,例如什么在这里创建锁/内存栅栏/屏障?所以我的问题是;我是否需要使字段线程安全,或者 async/await 结构中是否有某些内容负责处理此问题?
await将确保所有必要的内存屏障都已到位。然而,这并不意味着它们是“线程安全的”。
在这种情况下,InternalFireQueuedAsync 应始终在同一线程上调用。
然后_firing就好了,不需要volatile或类似的东西。
然而, 的用法_eventQueue是不正确的。考虑一下当线程池线程恢复了之后的代码时会发生什么await:完全有可能线程池线程同时被主线程调用Queue<T>.Count或将被调用。这不是线程安全的。Queue<T>.Dequeue()Queue<T>.Enqueue
如果主线程调用InternalFireQueuedAsync是具有单线程上下文的线程(例如 UI 线程),则一个简单的修复方法是删除ConfigureAwait(false)此方法中的所有实例。
| 归档时间: |
|
| 查看次数: |
12434 次 |
| 最近记录: |