找到并发计数器的最小值

时间:2013-03-07 20:00:04

标签: c++ concurrency thread-safety

我有几个计数器通过并发线程不断增加(从不减少)。每个线程负责一个计数器。有时,其中一个线程需要找到所有计数器的最小值。我通过对所有计数器的简单迭代来执行此操作并选择最小值。我需要确保这个最小值不超过任何计数器。目前,我不使用任何并发机制。我是否有机会得到错误的答案(即最终得到的最小值大于其中一个计数器)。代码大部分时间都有效,但偶尔(少于0.1%的时间),通过找到大于一个计数器的最小值来中断。我使用C ++代码,代码看起来像这样。

unsigned long int counters[NUM_COUNTERS];
void* WorkerThread(void* arg) {
  int i_counter = *((int*) arg);
  // DO some work
  counters[i_counter]++;
  occasionally {
    unsigned long int min = counters[i_counter];
    for (int i = 0; i < NUM_COUNTERS; i++) {
      if (counters[i] < min)
        min = counters[i];
    }
    // The minimum is now stored in min
  }
}

更新: 在使用@JerryCoffin建议的修复后,代码看起来像这样

unsigned long int counters[NUM_COUNTERS];
void* WorkerThread(void* arg) {
  int i_counter = *((int*) arg);
  // DO some work
  counters[i_counter]++;
  occasionally {
    unsigned long int min = counters[i_counter];
    for (int i = 0; i < NUM_COUNTERS; i++) {
      unsigned long int counter_i = counters[i];
      if (counter_i < min)
        min = counter_i;
    }
    // The minimum is now stored in min
  }
}

1 个答案:

答案 0 :(得分:4)

是的,它已经坏了 - 它有竞争条件。

换句话说,当你选出最小的值时,它无疑比你看到的任何其他值都小 - 但是如果另一个线程在你进行比较之后递增它,它可能会比其他一些计数器更大。你尝试使用它的时间。

 if (counters[i] < min)
        // could change between the comparison above and the assignment below
        min = counters[i];

比较和保存值之间的相对较短的间隔解释了为什么你得到的答案是大多数当时 - 如果在紧接着之后有一个上下文切换,那么它只会出错。比较,另一个线程在控制切换回来之前经常计数增量,它在保存时不再是最小的计数器。