2

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

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

4

4 回答 4

3

你可以在一个循环中伪造它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;
   }
}
于 2012-11-27T14:25:45.280 回答
1

我不认为您可以使用Interlocked. 我相信你必须切换到一个数组ints,以便每一位都在它自己的int.

Interlocked.CompareExchange仅比较相等性,而您只需要比较一个位,除非您使用其他一些并发策略来保护该位所在的int其他更改,否则您无法做到这一点。int

于 2012-11-27T14:21:07.957 回答
1

您需要线程安全的构造来跟踪并发任务的完成情况。因此,互锁结构总是比锁快(因为它们不需要锁),您应该Interlocked使用带有整数的 -class 中的静态方法(例如,0 等效于false1 true,例如 1)。

Jeffrey Richter 所做的与他在他的书“CLR via C#”第 28 章“原始线程同步构造”中所描述的相同。他还在他的 Wintellect.PowerThreading 库中介绍了基于 Interlocked 构造的自己的锁实现,并对他自己的实现和 .net 框架中包含的实现进行了出色的解释和时间比较。

于 2012-11-27T14:25:38.433 回答
1

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

那么该怎么做呢?

我会调查两个选项:

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

我不知道哪个最快。如果性能很重要,请对其进行基准测试。:)

于 2012-11-27T18:55:09.450 回答