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;

}

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

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

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

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