2011-02-27 113 views
0

用下面的代码:全部内存屏障和ExclusiveReceiverGroup

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 + = computationResult.Result完全内存屏障? ExclusiveReceiverGroup的Receiver注册中的处理程序将由线程池调用,因为dispatcherQueue不使用分派器。我读过线程池为它所调用的回调生成一个内存屏障,但这是否确保了回调引用本身的新鲜度?

ExclusiveReceiverGroup不会与任何其他代码同时运行,因此通过calculateResult.Result递增totalSum不必是原子的。我知道Interlocked.Add隐含地产生了一个完整的栅栏,但我只想看看我是否可以在没有使用的情况下离开。

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

回答

0

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

+0

你说得对,但是如果我们在DispatcherQueue中使用Dispatcher,似乎还是会产生内存障碍。分派器在它创建的线程上调用回调,对此没有内存屏障gaurantees(我相信)。在这种情况下,我们必须自己生成内存屏障,以确保我们使用的totalSum的值是来自主内存的全新副本。如果我们使用没有Dispatcher的DispatcherQueue,我们不必生成完整的内存屏障,因为ThreadPool为我们做了这些。这有意义吗? – 2011-03-04 16:54:05