博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
CAS无锁操作
阅读量:6836 次
发布时间:2019-06-26

本文共 3205 字,大约阅读时间需要 10 分钟。

主要讲的是《Implementing Lock-Free Queues》的论点,具体直接看论文最好。这里总结些要点。

CAS就是Compare And Swap。gcc可以调用:

1 __sync_bool_compare_and_swap

这段代码讲出无锁的两个关键手段:

1 EnQueue(x) //进队列 2 { 3     //准备新加入的结点数据 4     q = new record(); 5     q->value = x; 6     q->next = NULL; 7   8     do { 9         p = tail; //取链表尾指针的快照10     } while( CAS(p->next, NULL, q) != TRUE); //如果没有把结点链在尾指针上,再试11  12     CAS(tail, p, q); //置尾结点13 }

一个就是CAS,一个就是Retry-Loop。

然后,还有一个ABA问题,就是在被抢占之前和之后数据地址没变,但是数据内容可能变了。解决思路就是加一个额外的状态来记录(也可以用记数)。

 一个无锁队列的实现:

1 #include 
2 #include
3 #include
4 5 class CircleQueue { 6 public: 7 CircleQueue(int queue_count) { 8 this->queue_size_ = queue_count * sizeof(void*) + sizeof(unsigned long*) * 2; 9 this->queue_count_ = queue_count;10 shm_ = mmap(NULL, queue_size_, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS , -1, 0);11 memset(shm_, 0, queue_size_);12 head_ = (unsigned long*)shm_;13 tail_ = (unsigned long*)((char*)shm_ + sizeof(unsigned long));14 queue_ = (void**)((char*)shm_ + sizeof(unsigned long) * 2);15 }16 17 ~CircleQueue() {18 munmap(shm_, queue_size_);19 }20 21 int PushOneThread(void* ap) {22 if((int)(*head_ - *tail_) >= queue_count_) {23 return 1;//full24 }25 queue_[ *head_ % queue_count_ ] = ap;26 *head_ = *head_ + 1;27 return 0;28 }29 30 bool IsEmpty() {31 if(*head_ == *tail_) {32 return true;33 }34 return false;35 }36 37 int PopOneThread(void** ap) {38 if(*head_ == *tail_) {39 return 1;40 }41 42 if (ap == NULL) {43 return -1;44 }45 *ap = *(queue_ + *tail_ % queue_count_);46 *tail_ = *tail_ + 1;47 return 0;48 }49 50 int PopMultiThread(void** ap, int retry) {51 *ap = NULL;52 for(int i = 0; i < retry; ++i) {53 volatile unsigned long tail = *tail_;54 if(*head_ == tail) {55 return 1;56 }57 58 int ret = __sync_bool_compare_and_swap(tail_, tail, tail + 1);59 if(ret) {60 *ap = *( queue_ + (tail % queue_count_));61 return 0;62 }63 }64 return -1;65 }66 private:67 unsigned long* head_;68 unsigned long* tail_;69 void** queue_;70 void* shm_;71 int queue_size_;72 int queue_count_;73 };

这里的场景主要是一写多读。写的时候操作的是head,不需要加锁。读的时候,tail在改变的时候用上了CAS和retry-loop。 注意这里tail_只有在写的时候改变,而且只会往上加,所以不存在ABA问题。

p.s. 多进程通信的一个关键点,就是在于共享内存的时候,要确保所有的地址都是多进程共享的。所以这里存的指针,如果是多进程环境下,也应该是从共享内存中分配的。

转载于:https://www.cnblogs.com/linyx/p/9794617.html

你可能感兴趣的文章
JavaScript – 6.JS面向对象基础(*) + 7.Array对象 + 8.JS中的Dictionary + 9.数组、for及其他...
查看>>
格式资料python sqlalchemy 查询结果转化为 Json格式
查看>>
超链接浏览<meta name="format-detection"/> 的用法
查看>>
请求网络网络编程
查看>>
文件目录Android SDK目录结构
查看>>
Asp.net Web.Config - 配置元素customErrors
查看>>
Android: how to resolve Application’s parameter NullPointerException
查看>>
EntityFramework用法探索(二)CodeFirst
查看>>
人人都来写算法 之 快速排序
查看>>
[转]SQLServer和Oracle,存储过程区别,常用函数对比
查看>>
如何在ArcMap中监听键盘鼠标事件
查看>>
vs2012中程序集生成无法自动在网站Bin目录下生成Dll文件?(已解决!)
查看>>
fastDFS同步问题讨论
查看>>
ActiveMQ学习笔记(二) JMS与Spring
查看>>
实验室报告:VMware vSphere Data Protection
查看>>
php的数组与字符串的转换函数整理
查看>>
WCF 框架运行时类图
查看>>
spring配置异步执行
查看>>
软件开发报价的计算方法
查看>>
大型网站系统架构分析--转
查看>>