c++ - gcc 中的原子计数器

标签 c++ gcc

我一定是有时间,因为这应该很容易,但我似乎无法让它正常工作。

在 GCC 中实现原子计数器的正确方法是什么?

即我想要一个从 0 到 4 并且线程安全的计数器。

我正在做这个(进一步包装在一个类中,但不在这里)

static volatile int _count = 0;
const int limit = 4;

int get_count(){
  // Create a local copy of diskid
  int save_count = __sync_fetch_and_add(&_count, 1);
  if (save_count >= limit){
      __sync_fetch_and_and(&_count, 0); // Set it back to zero
  }
  return save_count;
}

但它是从 1 到 1 - 4(含),然后大约为零。
它应该从 0 到 3。通常我会用 mod 运算符做一个计数器,但我没有 知道如何安全地做到这一点。

也许这个版本更好。你能看到它有什么问题吗,或者提供 更好的解决方案。

int get_count(){
   // Create a local copy of diskid
   int save_count = _count;
   if (save_count >= limit){
      __sync_fetch_and_and(&_count, 0); // Set it back to zero
      return 0;
   }

   return save_count;
 }

实际上,我应该指出,每个线程获得不同的值并不是绝对重要的。如果两个线程碰巧同时读取相同的值,那将不是问题。但它们在任何时候都不能超过限制。

最佳答案

您的代码不是原子的(您的第二个 get_count 甚至不增加计数器值)!

假设 count 一开始是 3,两个线程同时调用 get_count。其中一个将首先完成他的原子添加并将 count 递增到 4。如果第二个线程足够快,它可以在第一个线程重置它之前将其递增到 5归零。

此外,在环绕处理中,您将 count 重置为 0 但不是 save_count。这显然不是预期的。

如果 limit 是 2 的幂,这将是最简单的。永远不要自己进行归约,只需使用

return (unsigned) __sync_fetch_and_add(&count, 1) % (unsigned) limit;

或者替代地

return __sync_fetch_and_add(&count, 1) & (limit - 1);

每次调用只执行一个原子操作,安全且非常便宜。对于通用限制,您仍然可以使用 %,但如果计数器溢出,这将破坏序列。您可以尝试使用 64 位值(如果您的平台支持 64 位原子)并希望它永远不会溢出;这是个坏主意。正确的方法是使用原子比较交换操作。你这样做:

int old_count, new_count;
do {
  old_count = count;
  new_count = old_count + 1;
  if (new_count >= limit) new_count = 0; // or use %
} while (!__sync_bool_compare_and_swap(&count, old_count, new_count));

这种方法也适用于更复杂的序列和更新操作。

也就是说,这种类型的无锁操作很难正确执行,在某种程度上依赖于未定义的行为(所有当前的编译器都正确执行此操作,但在 C++0x 实际具有明确定义的内存之前没有 C/C++ 标准型号)并且很容易折断。我建议使用简单的互斥锁/锁,除非您分析过它并发现它是一个瓶颈。

关于c++ - gcc 中的原子计数器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4161494/

相关文章:

java - 用于机器人技术的 c++ 或 java

c++ - 使用 Simulink Coder - 多维参数(矩阵、 vector )的原子变化

c - 警告 : data definition has no type or storage class

c++ - 如何为 C++ 函数定义属性别名?

c++ - c++什么时候实例化方法?

gcc - cygwin 64 位上的简单 gcc 编译

c++ - 如何找出lambda的自动类型参数中的哪些方法?

c++ - 类型 "char (&(...)) [2]"是什么意思?

c++ - 以混合(HYB)格式为CUDA中的稀疏矩阵分配内存?

c++ - 没有匹配功能 - 专门的签名隐藏通用?