0

我有几个计数器通过并发线程不断增加(从不减少)。每个线程负责一个计数器。有时,其中一个线程需要找到所有计数器中的最小值。我通过对所有计数器的简单迭代来做到这一点并选择最小值。我需要确保这个最小值不大于任何计数器。目前,我不使用任何并发机制。我是否有可能得到错误的答案(即,最终得到的最小值大于计数器之一)。该代码大部分时间都有效,但偶尔(不到 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
  }
}
4

1 回答 1

4

是的,它坏了——它有一个竞争条件。

换句话说,当您选择最小值时,它无疑比您看到的任何其他值都要小——但是如果在您进行比较后其他线程将其递增,那么在您尝试时它最终可能会大于其他某个计数器使用它。

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

比较和保存值之间相对较短的间隔解释了为什么您得到的答案在大多数情况下都是正确的——只有在比较之后立即发生上下文切换并且其他线程经常递增该计数器时才会出错在控制切换回来之前,它已经不再是最小的计数器了。

于 2013-03-07T20:06:35.010 回答