【问题标题】:Full memory barrier and ExclusiveReceiverGroup全内存屏障和 ExclusiveReceiverGroup
【发布时间】:2011-07-05 04:09:14
【问题描述】:

使用以下代码:

var dispatcherQueue = new DispatcherQueue();

long totalSum = 0;

Arbiter.Activate(
    dispatcherQueue,
    Arbiter.Interleave(
        new TeardownReceiverGroup(),
        new ExclusiveReceiverGroup(
            Arbiter.Receive<ComputationCompleteResult>(
                true,
                portSet,
                computationResult => totalSum += computationResult.Result
            ),
        new ConcurrentReceiverGroup(
            // Imagine that there is a persistent Receiver registered here
        )
    )
);

我是否需要围绕 totalSum += computeResult.Result 生成一个完整的内存屏障? ExclusiveReceiverGroup的Receiver注册中的handler会被线程池调用,因为dispatcherQueue不使用Dispatcher。我读过线程池会为其调用的回调生成内存屏障,但这是否只是保证回调引用本身的新鲜度?

ExclusiveReceiverGroup 不会与任何其他代码同时运行,因此通过 computeResult.Result 递增 totalSum 不必是原子的。我知道 Interlocked.Add 会隐式生成一个完整的围栏,但我只是想看看我是否可以不使用它而逃脱。

这是一个理论问题。我实际上没有像上面的示例代码那样的任何代码,也没有此类代码的任何用例。所以,我想避免“使用 Interlocked.Add 以防万一”的答案。这更像是一个“让我们学点新东西”的问题。

【问题讨论】:

    标签: c# concurrency robotics memory-barriers ccr


    【解决方案1】:

    我的理解是,因为ExclusiveReceiverGroup 在任何时候实际上只执行其委托的单个线程实例,所以不需要(进一步的)内存屏障。 ExclusiveReceiverGroup 的全部意义在于解决共享状态的有害问题,因此它是专门设计的,因此可以避免锁定。这与您使用的池/调度程序无关。

    【讨论】:

    • 你是对的,但如果我们在 DispatcherQueue 中使用 Dispatcher,我们似乎仍然需要生成内存屏障。 Dispatcher 在它创建的线程上调用回调,这些线程没有内存屏障保证(我相信)。在这种情况下,我们必须自己生成内存屏障,以确保我们使用的 totalSum 的值是来自主内存的新副本。如果我们在没有 Dispatcher 的情况下使用 DispatcherQueue,我们就不必生成完整的内存屏障,因为 ThreadPool 会为我们执行此操作。这有意义吗?
    猜你喜欢
    • 2022-09-23
    • 1970-01-01
    • 2012-07-02
    • 2014-09-11
    • 2014-02-04
    • 1970-01-01
    • 2011-09-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多