基于CAS实现无锁结构
杨乾成 2017310500302
一、题目要求
基于CAS(Compare and Swap)实现一个无锁结构,可考虑queue,stack,hashmap,freelist等。
- 能够支持多个线程同时访问该结构
- 不能有任何锁操作,且操作是线程安全的
- 对上述的内存单元进行管理,至少malloc与free一次。
二、数据结构
看到题目有一说一,不知道怎么下手,那就google一下先。稍微了解了一下CAS,原准备使用STL模板的队列,后来发现实现题目要求似乎得再Queue的插入和删除函数里面具体实现,于是决定自己实现吧(省事失败)。
先简要介绍一下CAS算法,我先po一下wiki百科上的代码介绍:
bool compare_and_swap (int *accum, int *dest, int newval)
{
if ( *accum == *dest ) {
*dest = newval;
return true;
}
return false;
}
这段代码的思想大概就是看看*dest里面的值和*accum里面的值是不是一样,如果一样,则将新数据写入。个人觉得用数据库的“脏数据”概念来形容很合适:即不允许往存有脏数据的缓冲区写入数值。在数据库中,常用的方法是两段锁,但是这里不让加锁。突然想起来大二上学期修JAVA里面讲到的同步信号量,即每当对数据结构进行操作时,就对=改变信号量的值,比如只有信号量值为0的时候才允许更改变量,修改时使用者将信号量置一,但是仔细一想,这似乎也是锁的思想。
遇事不决,再看看,害,现成的CAS都在这里,我直接用不就完事了。回归正题,CAS思想总结如下:线程操作钱保存当前版本号,也就是记录当前数据的状态的标志;当完成操作时,比较自己持有的版本号与当前版本号是否相符,相符则允许写入,否则获取的新的版本号再来一轮。就好像是大家都听说身边有个好看的姑娘处于“单身版本”,各自回去准备准备,第一个到的获得了优先权,后来的只能记住另一个“单身”的姑娘,再回家准备展开竞争,直到自己完成任务。
三、代码实现
#include<stdio.h>
#include<pthread.h>
#include <unistd.h>
#include <assert.h>
#include<stdlib.h>
#define THREAD_NUMBER 4
//队节点
typedef struct QNode
{
int data;
struct QNode *next;
}QNode, *QueuePtr;
//链队结构
typedef struct LinkQueue
{
QueuePtr front;
QueuePtr rear;
}LinkQueue; int is_Empty(LinkQueue *q);
void *pushThread(void *arg);
void *popThread(void *arg);
void init_Queue(LinkQueue *q);void cas_push(LinkQueue *q, int e);
void cas_push(LinkQueue *q, int e);
int cas_pop(LinkQueue *q, int *e);
void show(LinkQueue *q); int main()
{
LinkQueue que;
init_Queue(&que);
int i; //创建四个进程
pthread_t threadArr[THREAD_NUMBER]; //线程ID数组
for (i = ; i < THREAD_NUMBER; ++i)
{
pthread_create(&threadArr[i], NULL, pushThread, (void *)&que); //设置线程入口
}
//等待线程执行结束
for (i = ; i < THREAD_NUMBER; ++i)
{
pthread_join(threadArr[i], NULL);
}
show(&que); //创建四个进线程然后执行出队操作
for (i = ; i < THREAD_NUMBER; ++i)
{
pthread_create(&threadArr[i], NULL, popThread, (void *)&que);
}
for (i = ; i < THREAD_NUMBER; ++i)
{
pthread_join(threadArr[i], NULL);
}
exit(EXIT_SUCCESS);
} void *pushThread(void *arg)
{
printf("进程%ld开始创建队列:\n",pthread_self());
LinkQueue *quePtr =(LinkQueue *)arg;
int i;
for(i= ;i<;++i)
{
cas_push(quePtr, i);
}
printf("\n");
printf("完成队列创建操作!\n");
pthread_exit(NULL); //结束当前进程
} void *popThread(void *arg)
{
printf("%ld开始出队操作:\n",pthread_self());
LinkQueue *quePtr=(LinkQueue *)arg;
int temp;
int res;
while()
{
res = cas_pop(quePtr,&temp);
if(!res)
{
break;
}
printf("PID:%ld\tpop%d\n",pthread_self(),temp);
} } //初始化队列
void init_Queue(LinkQueue *q)
{
q->front=q->rear=(QNode *)malloc(sizeof(QNode));
q->front->next=NULL;
} //判断队列是否为空
int is_Empty(LinkQueue *q)
{
if(q->front->next ==NULL)
{
return ;
}
return ;
} void cas_push(LinkQueue *q, int e)
{
QueuePtr newNode = (QueuePtr)malloc(sizeof(QNode));
newNode->data = e;
newNode->next = NULL;
QueuePtr tmp;
//不断尝试将新节点进队
do
{
// sleep(1);
tmp = q->rear;
}while (!__sync_bool_compare_and_swap((long *)(&(tmp->next)), NULL, (long)newNode)); //判断此时队尾是否被改变
//就是在这里控制对队列的原子化操作
sleep();
q->rear = newNode;
} int cas_pop(LinkQueue *q, int *e)
{
QueuePtr tmp;
do
{
if (is_Empty(q))
{
return(); //队列已空,结束
}
tmp = q->front->next;
} while (!__sync_bool_compare_and_swap((long *)(&(q->front->next)), (long)tmp, (long)tmp->next));
sleep(); //通过休眠一秒,模拟线程操作时间,防止过快操作导致结果不明显
*e = tmp->data;
free(tmp);
return ;
} void show(LinkQueue *q)
{
printf("Current queue:\n");
QueuePtr tmp = q->front->next;
while (tmp)
{
printf("%d ", tmp->data);
tmp = tmp->next;
}
printf("\n");
}
上面就是这次的代码实现。
四、运行结果
使用指令:
gcc CAS_Structure.c -o result.out -lpthread
将源码进行编译,此处要注意后面一定要加上-lpthread,不然会提示“pthread.h”头文件报错问题。
我创建了四个进程,竞争往队尾插入数据。
然后竞争删除完队列的数据,直到队列为空。
从截图可以看出来,四个进程竞争着抢占处理器,直到完成创建和删除节点的任务。这里面要注意的是,因为实际处理就是插入节点,刚开始做的时候我没有插入sleep语句,所以最后的结果看起来像是顺序完成,所以要模拟实验,一定要注意加上sleep语句模拟进程处理的时间,防止第二个进程还没创建完,第一个进程早已完成了所有事务。
基于CAS实现无锁结构的更多相关文章
- paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象)
paip.提升性能----java 无锁结构(CAS, Atomic, Threadlocal, volatile, 函数式编码, 不变对象) 1 锁的缺点 2 CAS(Compare ...
- 使用CAS实现无锁的SkipList
无锁 并发环境下最常用的同步手段是互斥锁和读写锁,例如pthread_mutex和pthread_readwrite_lock,常用的范式为: void ConcurrencyOperation() ...
- 并发-AtomicInteger源码分析—基于CAS的乐观锁实现
AtomicInteger源码分析—基于CAS的乐观锁实现 参考: http://www.importnew.com/22078.html https://www.cnblogs.com/mantu/ ...
- AtomicInteger源码分析——基于CAS的乐观锁实现
AtomicInteger源码分析——基于CAS的乐观锁实现 1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时 ...
- 聊聊高并发(三十二)实现一个基于链表的无锁Set集合
Set表示一种没有反复元素的集合类,在JDK里面有HashSet的实现,底层是基于HashMap来实现的.这里实现一个简化版本号的Set,有下面约束: 1. 基于链表实现.链表节点依照对象的hashC ...
- AtomicInteger源码分析——基于CAS的乐观锁实
1. 悲观锁与乐观锁 我们都知道,cpu是时分复用的,也就是把cpu的时间片,分配给不同的thread/process轮流执行,时间片与时间片之间,需要进行cpu切换,也就是会发生进程的切换.切换涉及 ...
- CAS实现无锁模式
用多线程实现一个数字的自增长到1000000,分别用无锁模式和锁模式来实现代码. 1.使用ReentrantLock. package test; import java.util.concurren ...
- 使用CAS实现无锁列队-链表
#include <stdlib.h> #include <stdio.h> #include <pthread.h> #include <iostream& ...
- 图解kubernetes scheduler基于map/reduce无锁设计的优选计算
优选阶段通过分离计算对象来实现多个node和多种算法的并行计算,并且通过基于二级索引来设计最终的存储结果,从而达到整个计算过程中的无锁设计,同时为了保证分配的随机性,针对同等优先级的采用了随机的方式来 ...
随机推荐
- Oracle数据库的关键系统服务整理
在Windows 操作系统下安装Oracle 9i时会安装很多服务——并且其中一些配置为在Windows 启动时启动.在Oracle 运行在Windows 下时,有些服务可能我们并不总是需要但又害怕停 ...
- 【shell脚本】检查内存使用情况===chenkMen.sh
检查内存使用情况,当内存可使用等于100时,释放缓存 [root@localhost thy]# cat checkMem.sh #!/bin/bash #防止内存溢出问题 used=`free -m ...
- Python自定义注解
Python3.0之后加入新特性Decorators,以@为标记修饰function和class.有点类似c++的宏和java的注解.Decorators用以修饰约束function和class,分为 ...
- 最锋利的Visual Studio Web开发工具扩展:Web Essentials详解【转】
Web Essentials是目前为止见过的最好用的VS扩展工具了,具体功能请待我一一道来. 首先,从Extension Manager里安装:最新版本是19号发布的2.5版 然后重启你的VS开发环境 ...
- ABAP 新语法-实例讲解
主要内容 内联声明 构造表达式 内表操作 Open SQL 其他 本文列出了ABAP新语法的一些使用方式,供大家学习参考. 内联声明 代码实现: *&--------------------- ...
- SQL和T-SQL之间的区别
对于SQL,在我的上一篇博客中<何谓SQL Server数据库?与Access数据库 有什么区别>里面,已经着重说明了SQL作为访问和处理数据库的标准的计算机语言,所以这里就不做过多强调. ...
- Java基础之 集合体系结构(Collection、List、ArrayList、LinkedList、Vector)
Java基础之 集合体系结构详细笔记(Collection.List.ArrayList.LinkedList.Vector) 集合是JavaSE的重要组成部分,其与数据结构的知识密切相联,集合体系就 ...
- SPC软控件提供商NWA的产品在各行业的应用(包装行业)
Northwest Analytical (NWA)是全球领先的“工业4.0”制造分析SPC软件控件提供商.产品(包含: NWA Quality Analyst , NWA Focus EMI 和 N ...
- unlink remove
int unlink(const char *pathname); 删除一个文件的目录项并减少它的链接数 unlink()会删除参数pathname指定的文件.如果该文件名为最后连接点,但有其他进程打 ...
- 物联网通信 - RESTDemo示例程序(Java版本)
源码下载 -> 提取码 QQ:505645074 Netty的Restful API实现 Get: http://127.0.0.1:8662/test Post http://127.0. ...