c语言 无锁编程,无锁编程与有锁编程的效率总结、无锁队列的实现(c语言)「建议收藏」

c语言 无锁编程,无锁编程与有锁编程的效率总结、无锁队列的实现(c语言)「建议收藏」1.无锁编程与有锁编程的效率无锁编程,即通过CAS原子操作去控制线程的同步。如果你还不知道什么使CAS原子操作,建议先去查看相关资料,这一方面的资料网络上有很多。CAS实现的是硬件级的互斥,在线程低并发的情况下,其性能比普通互斥锁高效,但是当线程高并发的时候,硬件级互斥引入的代价与应用层的锁竞争产生的代价同样都是很大的。这时普通锁编程其实是优于无锁编程的。硬件级原子操作使应用层的操作变慢,而且无法…

大家好,又见面了,我是你们的朋友全栈君。

1.无锁编程与有锁编程的效率

无锁编程,即通过CAS原子操作去控制线程的同步。如果你还不知道什么使CAS原子操作,建议先去查看相关资料,这一方面的资料网络上有很多。

CAS实现的是硬件级的互斥,在线程低并发的情况下,其性能比普通互斥锁高效,但是当线程高并发的时候,硬件级互斥引入的代价与应用层的锁竞争产生的代价同样都是很大的。这时普通锁编程其实是优于无锁编程的。

硬件级原子操作使应用层的操作变慢,而且无法再进行优化。如果对有锁多线程程序有良好的设计,那么可以使程序的性能在不下降的同时,实现高并发。

2.无锁编程的好处

无锁编程不需要程序员再去考虑死锁、优先反转等棘手的问题,因此在对应用程序不太复杂,而对性能要求稍高的程序中,可以采取有锁编程。如果程序较为复杂,性能要求不高的程序中可以使用无锁编程。

3.无锁队列的实现

对于线程无锁同步方式方式的应用,我实现了一个无锁的队列。首先看一下程序的运行结果:

5389fffa2b83f4d5b2223d91bb76b263.png

程序的运行结果符合队列先进先出的特点。

关于一些细节的问题在代码中都有详细的注释,请参见代码:

#include #include#include#include#include//用链表实现队列

//节点结构

typedef struct Node

{

struct Node *next;

int data;

}node;

//队列的定义

typedef struct Queue

{

node* front;

node* rear;

}queue;

//定义一个全局的队列

queue que;

//队列的初始化操作

void QueInit(queue *que)

{

//申请一个新的节点

node *temp = (node*)malloc(sizeof(node));

assert(temp!=NULL);

temp->next=NULL;

que->front=que->rear=temp;

}

//队空判断

int QueEmpty()

{

return __sync_bool_compare_and_swap(&(que.rear),que.front,que.front);

}

//入队操作

void QuePush(int *d)

{

//申请新节点

node *temp = (node*)malloc(sizeof(node));

assert(temp!=NULL);

temp->data=*d;

//将新申请的节点利用原子操作插入到队列当中

node* p;

do

{

p = que.rear;

}

while(!__sync_bool_compare_and_swap(&(p->next),NULL,temp));

//重置尾指针

__sync_bool_compare_and_swap(&(que.rear),p,temp);

}

//出队操作

int QuePop(int *d)

{

//temp为要输出的元素

node *temp;

//因为temp可能为NULL,因此我们用P记录temp->next的值,后续会用到

node *p;

do

{

if(QueEmpty())

return 0;

temp = que.front->next;

if(temp!=NULL)

p=temp->next;

else

p=NULL;

}

while(!__sync_bool_compare_and_swap(&(que.front->next),temp,p));

//更新尾指针

__sync_bool_compare_and_swap(&(que.rear),temp,que.front);

if(temp!=NULL)

{

*d = temp->data;

free(temp);

return 1;

}

return 0;

}

//两个线程函数:一个入队,一个出队

void * thread_push(void *arg)

{

while(1)

{

int data = rand()%100;

QuePush(&data);

printf(“队列插入元素:%d\n”,data);

sleep(1);

}

}

void *thread_pop(void *arg)

{

int data;

while(1)

{

sleep(2);

if(!QuePop(&data))

printf(“队列为空\n”);

else

printf(“队列输出元素:%d\n”,data);

}

}

int main()

{

//初始化队列

QueInit(&que);

//创建两个线程

pthread_t id[2];

pthread_create(&id[0],NULL,thread_push,NULL);

pthread_create(&id[1],NULL,thread_pop,NULL);

//等待线程结束

pthread_join(id[0],NULL);

pthread_join(id[1],NULL);

//在这之后还因该删除队列回收内存

//删除队列不涉及多线程操作,不再赘述

return 0;

}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/134202.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • JAVA8 Stream学习

    JAVA8 Stream学习

    2021年11月12日
  • 【Android】PreferenceFragment「建议收藏」

    【Android】PreferenceFragment「建议收藏」调用PreferenceFragment类出错,用了我三天时间才搞定,查官方文档,看百度最后在这位大佬的帖子帮助下终于搞定了。https://blog.csdn.net/cqx13763055264/article/details/78498419#commentBoxPreferenceActivity创建和使用比较复杂,Android官方现在不建议使用了,使用Preferenc…

  • oracle与mysql的存储区别_存储过程和触发器的区别和联系

    oracle与mysql的存储区别_存储过程和触发器的区别和联系1.创建存储过程语句不同oraclecreateorreplaceprocedureP_ADD_FAC(id_fac_cdINES_FAC_UNIT.FAC_CD%TYPE)asmysqlDROPPROCEDUREIFEXISTS`SD_USER_P_ADD_USR`;createprocedureP_ADD_FAC(id_fac_…

  • aop 实现原理_注解的实现原理

    aop 实现原理_注解的实现原理转载地址:https://my.oschina.net/elain/blog/382494一、什么是AOPAOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-OrientedPrograming,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入…

  • 小程序onready和onload_公众号小程序

    小程序onready和onload_公众号小程序onLoad:页面第一次加载时触发,从跳转页面返回时不能触发,可以传递参数onShow:页面显示或从后台跳回小程序时显示此页面时触发,从跳转页面返回时触发,不能传递参数onHide:页面隐藏,例如使用wx.navigateTo只是打开新页面并不关闭原页面onUnload:页面被卸载,例如使用wx.redirectTo重定向一个页面原页面已经关闭当初始化或打开一个新…

  • 查看端口是否被占用 linux_如何查看8080端口是否被占用

    查看端口是否被占用 linux_如何查看8080端口是否被占用之前查询端口是否被占用一直搞不明白,问了好多人,终于搞懂了,现在总结下:1.netstat-anp|grep端口号如下,我以3306为例,netstat-anp|grep3306(此处备注下,我是以普通用户操作,故加上了sudo,如果是以root用户操作,不用加sudo即可查看),如下图1:图1图1中主要看监控状态为LISTEN表示已经被占用,最后一列显示被服务mysqld占用,查看具…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号