Sometimes I encounter async/await code that accesses fields of an object. For example this snippet of code from the Stateless project:
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;
}
}
If I understand correctly the await **.ConfigureAwait(false)
indicates that the code that is executed after this await
does not necessarily has to be executed on the same context. So the while
loop here could be executed on a ThreadPool thread. I don't see what is making sure that the _firing
and _eventQueue
fields are synchronized, for example what is creating the a lock/memory-fence/barrier here? So my question is; do I need to make the fields thread-safe, or is something in the async/await structure taking care of this?
Edit: to clarify my question; in this case InternalFireQueuedAsync
should always be called on the same thread. In that case only the continuation could run on a different thread, which makes me wonder, do I need synchronization-mechanisms(like an explicit barrier) to make sure the values are synchronized to avoid the issue described here: http://www.albahari.com/threading/part4.aspx
Edit 2: there is also a small discussion at stateless: https://github.com/dotnet-state-machine/stateless/issues/294