可以使用Interlocked.CompareExchange和Bit吗?

时间:2012-11-27 14:11:37

标签: c# arrays multithreading task-parallel-library interlocked

我有一个跟踪10,000个并发任务完成的整数数组,其值为1或0.我认为如果这个数组是Bits数组并且每个并发线程使用了interlocked.CompareExchange会更有效率(或类似的)改变一个位。

如果Interlocked没有“bit”过载,我该如何处理?

4 个答案:

答案 0 :(得分:2)

您可以在循环中使用Interlocked.CompareExchange(ref int, int, int)伪造它,但我认为它不会更有效:

private static void SetBit(ref int valueToUpdate, int bitToSet)
{
   while (true)
   {
      int oldValue = valueToUpdate;
      int newValue = oldValue | bitToSet;
      int result = Interlocked.CompareExchange(ref valueToUpdate, newValue, oldValue);
      if (result == oldValue) break;
   }
}

答案 1 :(得分:1)

我认为您不能使用Interlocked来使用位。我相信你必须切换到ints的数组,这样每个位都在它自己的int内。

Interlocked.CompareExchange只比较相等,而你只需要比较int中你不能做的一个比特,除非你使用其他并发策略来保护int的其他变化比特位于。

答案 2 :(得分:1)

您需要线程安全的构造来跟踪并发任务的完成情况。因此,互锁结构总是比锁更快(因为它们不需要锁),你应该使用Interlocked - 类中的静态方法和整数(0代表{{1例如,false为1。}。

杰弗里·里希特(Jeffrey Richter)在第28章“原始线程同步构造”(Primitive Thread Synchronization Constructs)中对他的书“CLR via C#”中所描述的做法也是如此。他在Wintellect.PowerThreading库中引入了基于Interlocked结构的自己的锁实现,并给出了一个很好的解释,以及他自己的实现和.net框架中包含的实现的时间比较。

答案 3 :(得分:1)

首先,不,所有互锁功能都在内存地址上工作,并且各个位不可寻址。

那么该做什么呢?

我会调查两个选项:

  • 根本不打扰数组:有一个简单的计数器,每次任务完成时都会InterlockedIncrement。要查看是否所有任务都已完成,只需检查该值是否已达到10,000。
  • 或者,使用该阵列,以最小化(错误)数据共享。但是你不应该试图密集地包装它。走相反的道路。确保每个条目最终都位于单独的CPU缓存行上,以便并行运行的任务不会在同一缓存行上进行争用。 (然后,由于任务都写入不同的位置,他们甚至不必使用昂贵的互锁操作设置“完成”标志。)

我不知道哪个是最快的。如果表现很重要,那就进行基准测试:)