C++11 在 0 时uint64_t个循环的原子递减
c++11 atomic decrement of uint64_t cycles at 0
我正在尝试编写一个简单的并行处理系统,该系统应该生成N个对象以放入多线程环境中的容器中。
为了告诉线程何时停止生成对象,我创建了一个简单的反向计数器,该计数器从 N 开始,从 0 开始,每个线程并行递减。计数器应该是uint64_t,我想尝试C++11的原子支持。代码如下所示
//Class member
std::atomic<uint_fast64_t> counter
//Parallel function
while(counter-- > 0)
{
do something
}
它正确编译并执行,但它进入无限循环,因为一旦计数器达到 0,它就会进一步递减,但它会跳回到可用的最高整数,从而永远不会停止。
将类型更改为 int64 而不是 uint64 可以解决问题,但我想了解为什么我需要这种解决方法。
我目前的工作假设是,即使条件为假,递减也会完成,所以当第一个线程检查计数器为 0 时,它无论如何都会递减它,并且运算减法运算并不真正关心整数的编码,但执行简单的按位运算(我完全忘记了是哪一个,但我记得加法和减法是通过简单的按位异或和移位完成的),其中下一次迭代被解释为最大 uint 值。你觉得这个解释合理吗?
除了从 uint 切换到 int 之外,一个选项是将操作从递减切换到递增,但你能想到一种不同的算法来保持这种上下文中的递减吗?
编辑1
我想到的另一个可能的解决方案,即使不是特别优雅,是知道实际并行启动了多少线程,在起始值为 Tot+NThreads 的 N_Threads 处停止计数器
//In calling function
counter = Tot+NThreads
//Parallel function
while(counter-- > NThreads)
{
do something
}
原子性仅保证所有线程都看到一致的atomic
值值。通常,像--
这样的操作是读取-修改-写入操作。atomic
仅保证没有其他线程修改计数器,而另一个线程正忙于修改计数器。
澄清一下:atomic
防止数据竞争,没有别的。
假设两个线程,T1 和 T2 以及下面的 R、M、W 序列:现在线程 T2 的结果已被 T1 的结果覆盖,即计数器的值不一致。
T1:读取 T2:读取 T2:修改T1:修改 T2:写入 T1:写入
因此,在您的问题中,代码执行counter--
这意味着无论其值如何,--
都将始终完成。因此,如果该值已经为零,则现在将为 -1,或者在使用unsigned
数据类型时,为 unsigned
类型的最大值。
你的假设
这或多或少是正确的。 (unsigned) 0 - 1
将是最大的无符号整数。你的原子递减总是会发生的,即使条件是假的。
我们如何解决这个问题?
我相信您实际上正在寻找这样的东西:
std::atomic<uint_fast64_t> counter;
while (true) {
uint_fast64_t cur = counter;
if (cur == 0)
break;
if (counter.compare_exchange_strong(cur, cur - 1) == false)
continue;
... // Perform work
}
首先,我们测试计数器的当前值是否为 0。如果是这样,我们就完成了工作,我们应该退出。
如果它大于 0,那么我们需要递减计数器。这是一个比较和交换操作。因此,如果值在到达第二个原子操作所需的时间内没有变化,我们执行递减,然后做一些工作。如果我们被抢占了,那么我们只会再试一次。
- 如何循环打印顶点结构
- 如何在C++中从两个单独的for循环中添加两个数组
- C++我的数学有什么问题,为什么我的代码不能正确循环
- 正在尝试了解输入验证循环
- std::map<struct,struct>::find 找不到匹配项,但是如果我循环通过 begin() 到 end(),我在那里看到匹配项
- 循环后如何继续阅读
- Ardunio UNO解决了多个重叠的定时器循环
- Eigen如何在容器循环中干净地附加矩阵
- 在某些循环内使用vector.push_back时出现分段错误
- 我正在使用嵌套的while循环来解析具有多行的文本文件,但由于某种原因,它只通过第一行,我不知道为什么
- 为什么我的for循环不能正确获取argv
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- while循环中while循环的时间复杂度是多少
- C++中的高效循环缓冲区,它将被传递给C样式数组函数参数
- 为什么在这个代码结束循环中没有得到结束
- 在基于范围的for循环中使用结构化绑定声明
- 用于C++中带有数组和指针的循环
- 循环中的随机函数
- 是什么阻止DOMTimerCoordinator::NextID进入无休止的循环
- 在循环C++中指定字符串之后,不会打印该字符串