3

我知道 int 在内存中不会有固定的位置,所以它根本不能那样工作。但是完全相同的代码部分将使用不同的名称、参数等同时运行

我需要传递一个“名称”字符串,然后以某种方式增加我的 int 数组中的一个项目。

Dictionary<string, int> intStats = new Dictionary<string, int>();

该字典根据作为字典字符串键提供的“名称”存储所有统计信息。

而且由于我使用了很多多线程,我希望保持 int 计数尽可能同步。这就是为什么我试图使用Interlocked.Increment(ref intStats[theName]); 但不幸的是这不起作用。

有没有适合我的情况的替代方案?

4

1 回答 1

3

首先,我建议创建一个自定义类型来捕获抽象数据类型的语义。这样你就可以试验不同的实现,这样你的呼叫站点就可以自我记录。

internal sealed class NameCounter
{
  public int GetCount(string Name) { ... }
  public void Increment(string Name) { ... }
}

那么:鉴于这必须是线程安全的,您可能会做出哪些实现选择?

  • 私人Dictionary<string, int>可以工作,但您必须在每次访问时锁定字典,这可能会变得昂贵。

  • 一个 private ConcurrentDictionary<string, int>,但请记住,您必须TryUpdate 在循环中使用以确保您不会丢失值。

  • 制作一个包装器类型:


internal sealed class MutableInt
{
  public int Value;
}

这是您想要创建公共字段的罕见情况之一。现在制作一个ConcurrentDictionary<string, MutableInt>,然后InterlockedIncrement是公共领域。现在您不必这样做TryUpdate,但这里仍然存在竞争:如果两个线程都第一次尝试同时添加相同的名称,那么您必须确保只有一个线程获胜。小心使用AddOrUpdate以确保这场比赛不会发生。

  • 将您自己的并发字典实现为索引到 int 数组的哈希表;InterlockedIncrement在数组的元素上。同样,当将新名称引入系统时,您必须非常小心,以确保以线程安全的方式检测到哈希冲突。

  • 将字符串散列到 n 个存储桶之一,但这次存储桶是不可变字典。每个桶都有一把锁;锁定桶,从旧字典创建一个新字典,将其放回桶中,解锁桶。如果存在争用,则增加 n 直到它消失。

于 2018-03-10T00:28:09.383 回答