无锁编程与有锁编程的效率总结、无锁队列的实现(c语言)

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

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

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

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

2.无锁编程的好处

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

3.无锁队列的实现

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

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

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

#include <stdio.h>
#include<unistd.h>
#include<stdlib.h>
#include<pthread.h>
#include<assert.h>
//用链表实现队列
//节点结构
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;
}

发布了143 篇原创文章 · 获赞 35 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/qq_42214953/article/details/105750215
今日推荐