如果我有两个
std::atomic<int>
计数器,a
和 b
(都只做增量)。我想要做的是如果严格小于 a
,则增加 b
,并返回 a 的旧值。在存在多个线程都尝试此操作的情况下,我可以在不使用锁的情况下完成此操作吗?
比较然后递增序列需要锁定以确保
a
在比较和递增之间不会改变
由于
a
和 b
严格递增,您可以使用 compare_exchange
来完成此操作。这个想法是,将 a
和 b
的值加载到局部变量中,比较这些局部变量,如果有必要,当且仅当它仍然等于其旧值时,尝试将 local_a+1 交换到 a
中(这正是比较交换确实)。如果失败,则表明其他人已成功更新a
,因此您重试,包括比较。
int inc()
{
// Load b and an into locals.
int aVal = a;
int bVal = b;
while(aVal < bVal)
{
if (a.compare_exchange_weak(aVal, aVal+1))
{
// Success! Return the original value of a.
return aVal;
}
// Note that if a compare_exchange fails then `aVal` will already be updated with the new value of `a` so we only need to reload `b`
bVal = b;
}
// a >= b so don't do anything
return -1;
}
您可能可以收紧加载和比较/交换的内存顺序,但这是最简单的版本。
还要注意,虽然其中有一个循环,但循环是非常正常的(事实上,compare_exchange 的 weak 版本是必需的),因此不必担心 - 这是因为对于每次迭代循环的至少一个线程已成功执行工作,因此系统作为一个整体的前进总是会发生。