如何在 C++ 中为共享计数器实现简单的比较和交换
Posted
技术标签:
【中文标题】如何在 C++ 中为共享计数器实现简单的比较和交换【英文标题】:how to implement simple Compare And Swap in C++ for shared counter 【发布时间】:2018-02-15 07:46:56 【问题描述】:我正在尝试学习没有锁的并发性。因此,我试图为共享变量计数器实现简单的比较和交换(cas)。我尝试创建 10 个线程,并希望使用 CAS 将每个线程的计数器值增加 1。因为 CAS 存储旧值并与当前值进行比较,并且仅在值未更改时才更新。寻找[这里] 我尝试实现 CAS,但无法正确执行。 c++中如何实现计数器共享变量的CAS?
#include <iostream>
#include <thread>
#include <unistd.h>
#include <atomic>
std::atomic<int> count = 0;
std::mutex n_mutux;
void increase_counter(int i)
int old_value = count.load() ;
while (!count.compare_exchange_weak(old_value, old_value +1))
int main()
int thread_num =10;
std::thread t[thread_num];
for(int i=0;i<thread_num;i++)
t[i]=std::thread((increase_counter),i);
for(int i=0;i<thread_num;i++)
t[i].join();
std::cout<<count;
【问题讨论】:
你应该在你的 while 循环中更新 old_valuestd::thread((increase_counter), i)
中的括号是干什么用的?
@FlorianM。我正在尝试使用 oldvalue +1 进行更新。计数初始化为原子共享变量是否正确??
@DeanSeo increase_counter 是每个线程使用 i 调用的函数,以防需要线程 ID。
代码似乎是正确的。什么是问题?您是否从std::cout<<count;
得到意外输出?还是什么?
【参考方案1】:
你的解决方案是正确的。
另一种方法是使用增量,请参阅std::atomic::operator++()
或fetch_add(1, std::memory_order_acq_rel)
。这两个不需要繁忙的等待循环。
std::atomic<int> count = 0
的初始化存在编译器错误。修复:
std::atomic<int> count0;
更高效的 CAS 是:
void increase_counter(int i)
int old_value = count.load() ;
while(!count.compare_exchange_weak(old_value, old_value + 1,
std::memory_order_release,
std::memory_order_relaxed))
_mm_pause();
Pause Intrinsic:
pause
内在函数用于自旋等待循环,处理器实现动态执行(尤其是乱序执行)。在自旋等待循环中,pause
内在函数提高了代码检测锁释放的速度,并提供了特别显着的性能增益。下一条指令的执行会延迟一段特定于实现的时间。
pause
指令不会修改架构状态。对于动态调度,pause
指令减少了退出自旋循环的惩罚。
有关更多详细信息和基准,请参阅Benefitting Power and Performance Sleep Loops。
【讨论】:
以上是关于如何在 C++ 中为共享计数器实现简单的比较和交换的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Linux 上的 C++ 程序中使用共享库(在本例中为 JsonCpp)?
C++ String的引用计数写时复制 的实现 《More Effective C++》