c# - 使用 async/await 时是否需要使字段线程安全?

标签 c# multithreading asynchronous async-await task-parallel-library

有时我会遇到访问对象字段的异步/等待代码。例如这个 snippet来自 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 之后执行的代码执行 not necessarily必须在相同的上下文中执行。所以这里的 while 循环可以在 ThreadPool 线程上执行。我看不出是什么确保 _firing_eventQueue 字段是同步的,例如,是什么在这里创建了锁/内存栅栏/屏障?所以我的问题是;我需要使字段线程安全,还是异步/等待结构中的某些东西负责这个?

编辑:澄清我的问题;在这种情况下,应始终在同一线程上调用 InternalFireQueuedAsync。在那种情况下,只有延续可以在不同的线程上运行,这让我想知道,我是否需要同步机制(如显式屏障)来确保值同步以避免此处描述的问题:http://www.albahari.com/threading/part4.aspx

编辑 2:在 stateless 上也有一个小讨论: https://github.com/dotnet-state-machine/stateless/issues/294

最佳答案

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?

await将确保所有必要的内存屏障都到位。然而,这并不能使它们成为“线程安全的”。

in this case InternalFireQueuedAsync should always be called on the same thread.

然后_firing很好,不需要 volatile或类似的东西。

但是,_eventQueue 的用法是不正确的。考虑当线程池线程在 await 之后恢复代码时会发生什么: 完全有可能 Queue<T>.CountQueue<T>.Dequeue()将同时被一个线程池线程调用Queue<T>.Enqueue被主线程调用。这不是线程安全的。

如果主线程调用InternalFireQueuedAsync是具有单线程上下文的线程(例如 UI 线程),那么一个简单的解决方法是删除 ConfigureAwait(false) 的所有实例在这个方法中。

关于c# - 使用 async/await 时是否需要使字段线程安全?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53649448/

相关文章:

c# - 在 LINQ 查询中,include 和 where 的顺序是否重要?

javascript - DeprecationWarning : Calling an asynchronous function without callback is deprecated. - 如何找到 "function:"在哪里?

c - 用于异步 I/O 的 librt 和 libeio 之间有什么区别,我为什么要选择其中之一?

c# - 在这种情况下使用按位与 (&)

c# - 如何与USB 3G调制解调器通信?

c# - 当我更新应用程序时文件会发生什么?

c++ - 更新 CListCtrl 时 MFC 应用程序卡住

php - 在屏幕上向用户使用php显示页面时,在后台执行shell脚本

c# - "lock(obj) {/* empty */}"对线程可见性的影响

javascript - 异步 waterfall : Callback already was called?