Иногда я сталкиваюсь с асинхронным / ожидающим кодом, который обращается к полям объекта.Например, этот фрагмент кода из проекта Stateless:
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;
}
}
Если я правильно понимаю, 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