【发布时间】:2015-03-15 18:46:01
【问题描述】:
我正在尝试编写一个简单的并行处理系统,它应该生成 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
我想到的另一个可能的解决方案,虽然不是特别优雅,但知道实际并行启动了多少线程,将计数器停止在 N_Threads 处,起始值为 Tot+NThreads
//In calling function
counter = Tot+NThreads
//Parallel function
while(counter-- > NThreads)
{
do something
}
【问题讨论】:
-
当然可以,你告诉它的。如果计数器为零,它会递减并退出。所有其他线程现在都在疯狂地减少现在非常高的计数器,没有希望取得重大进展。
-
为什么不在while循环内做减量?
-
@Moberg:考虑两个线程的情况。因为
counter == 1,两者都进入了while循环。然后,一旦两者都在循环中,它们都会递减counter。现在counter == -1。 -
正如比尔·林奇所说,如果你在两个不同的地方进行变量评估和递减,你不能保证在此期间没有其他人在做同样的事情
-
while(counter-- > NThreads)的性能并不比while(counter++ < NThreads)高,而且惯用语也明显低于while(counter++ < NThreads)。
标签: c++ multithreading c++11 atomic decrement