设为首页 收藏本站
查看: 967|回复: 0

[经验分享] C++11 CAS无锁函数compare_exchange_weak的使用

[复制链接]

尚未签到

发表于 2015-11-24 14:41:33 | 显示全部楼层 |阅读模式
  关于C++11的并发指南可以看这个Blog。
  这里主要想谈一下对compare_exchange_weak这个C++11用来实现CAS无锁算法函数的理解。

可以先看一下cplusplus给出的用这个函数实现无锁链表的例子:

// atomic::compare_exchange_weak example:
#include <iostream>       // std::cout
#include <atomic>         // std::atomic
#include <thread>         // std::thread
#include <vector>         // std::vector
// a simple global linked list:
struct Node { int value; Node* next; };
std::atomic<Node*> list_head (nullptr);
void append (int val) {     // append an element to the list
Node* oldHead = list_head;
Node* newNode = new Node {val,oldHead};
// what follows is equivalent to: list_head = newNode, but in a thread-safe way:
while (!list_head.compare_exchange_weak(oldHead,newNode))
newNode->next = oldHead;
}
int main ()
{
// spawn 10 threads to fill the linked list:
std::vector<std::thread> threads;
for (int i=0; i<10; &#43;&#43;i) threads.push_back(std::thread(append,i));
for (auto& th : threads) th.join();
// print contents:
for (Node* it = list_head; it!=nullptr; it=it->next)
std::cout << ' ' << it->value;
std::cout << '\n';
// cleanup:
Node* it; while (it=list_head) {list_head=it->next; delete it;}
return 0;
}
  Possible output (the order may be different):

9 8 7 6 5 4 3 2 1 0
  对函数参数和返回&#20540;的解释可以看原文,或翻译。
  归纳一下这个函数的使用要点:



  • 当前&#20540;与期望&#20540;相等时,修改当前&#20540;为设定&#20540;,返回true
  • 当前&#20540;与期望&#20540;不等时,将期望&#20540;修改为当前&#20540;,返回false
  • 这个函数可能在满足true的情况下仍然返回false,所以只能在循环里使用,否则可以使用它的strong版本

  不过我觉得那个strong版本(compare_exchange_weak)应用场景的意义&#20284;乎不大,因为是一次执行,可以完全用atomic_flag的testandset操作代替。

而这个weak版本考虑到了硬件性能的最优化,在使用CAS时一般都只会用到它。

相比无锁链表或者无锁队列,更一般的用法应该是这样的:

1 auto max_val = getMaxValue();//获取&#20540;上界
2 auto now_val = getValue();//获取当前&#20540;
3 auto exp_val = now_val; //期望&#20540;为当前&#20540;
4 do {
5   if(exp_val == max_val) break; //到达上界退出循环
6 } while(!now_val.compare_exchange_weak(exp_val, exp_val &#43; 1))//从第2行到第5行代码可能被其他线程中断改变now_val的&#20540;
  这段代码简要地说明了这个函数的使用方法,首先你要持有一个now_val,接着在企图修改这个&#20540;时,用CAS函数来判断这个&#20540;是否发生了改变,如果未改变则执行加1,若改变了则期望&#20540;随之改变为该当前&#20540;,直到循环判断到期望&#20540;与当前&#20540;相等,再执行加1操作。

可能你会觉得这不就是原子加1,用atomic自带的加法重载不就实现了。其实这里还有一个用处,也就是对期望&#20540;(或当前&#20540;)进行判断,比如当到达一个临界&#20540;以后就停止累加,原子加法没法将加1之后的判断也绑定到同一个原子操作中,也就没法实现这一点。而CAS的循环体中则可以实现一个“准改判断”——不满足条件就不允许修改当前&#20540;。
  打个不恰当的比方,就像一个备胎等待老司机换胎,想着“下一个就轮到自己了”,结果发现下一个是别人,于是又想“下一个就是自己了”,“下一个就是自己了”...到最后橡胶老化被司机扔了...XD

Let my exciting burning magma fulfill the infinite void black hole.

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-143158-1-1.html 上篇帖子: Exchange 2007 打开POP3 及 IMAP4端口 下篇帖子: POJ 1860:Currency Exchange(Bellman_Ford算法)
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表