• Linux中自旋锁实现的基本原理之经典


    目录

    一、自旋锁基本简介

    二、自旋锁和互斥锁之间的区别

    三、自旋锁API函数

    四、自旋锁代码实现

    五、互斥锁实现

    运行结果:

    总结:


    线程:线程是进程资源分配的最小单位,每个进程都有的自己的main(主线程)

    线程同步:多个线程按顺序以此执行访问共享资源(数据)。

    线程同步的必要性:防止多线程并发访问共享数据的时候出现数据混乱、不一致 的问题。

    线程同步的方法:互斥锁、自旋锁、条件变量....

    实例:创建两个线程轮流计数

     

    #include

    #include

    #include

    #include

    #include

    int q_cont;     //计数值

    long loops;     //计数次数

    void *task(void *arg)

    {

        long num=(long)arg;

        int j_cont=0;

        int i;

        for(i=0;i

        {

            //计数

            j_cont=q_cont;

            j_cont++;

            q_cont=j_cont;

        }

        pthread_exit(NULL);

    }

    int main(int aegc,char *argv[])

    {

        int i;

        pthread_t tid1,tid2;

        loops=atoi(argv[1]);

      

        //创建线程      

        pthread_create(&tid1,NULL,task,(void *)loops);

        pthread_create(&tid2,NULL,task,(void *)loops);

        //等待线程结束

        pthread_join(tid1,NULL);

        pthread_join(tid2,NULL);

        //打印次数

        printf("q_cont=%d\r\n",q_cont);

        return 0;

    }

    一、自旋锁基本简介

    自旋锁本质上是一把锁,在访问共享资源之前对自旋锁进行上锁,在访问完成后释放自旋锁(解锁)

    从实现方式上来说,互斥锁是基于自旋锁来实现的,所以自旋锁相比较于互斥锁更加底层。

         

    二、自旋锁和互斥锁之间的区别

    互斥锁

    自旋锁

    等待方式

    阻塞(休眠)

    自旋(不停申请)

    效率

    低(休眠、唤醒开销大)

    应用场景

    进程上下文

    中断上下文

    缺点

    1. 不能放在中断服务函数中,易锁死
    2. 开销大

    自旋占用CPU资源,不适用于长时间等待

    三、自旋锁API函数

    1、pthread_spin_init() 初始化函数

    原型:int pthread_spin_init(pthread_spinlock_t *lock ,int pshared);

    参数:pthread_spinlock_t *lock pthread_spinlock_t 定义的锁

    int pshared PTHREAD_PROCESS_PRIVATE

    PTHREAD_PROCESS_SHARED

    PTHREAD_PROCESS_PRIVATE  自旋锁只能在同一进程中的线程进行操作。

    PTHREAD_PROCESS_SHARED  自旋锁可以由任何进程中的任何线程操作。

    2、pthread_spin_lock(pthread_spinlock_t *lock) 加锁函数

    3、pthread-spin_unlock(pthread_spinlock_t *lock) 解锁函数

    4、pthread_spin_destroy(pthread_spinlock_t *lock) 摧毁锁函数

    补充:

    pthread_spin_trylock(pthread_spinlock_t *lock) 加锁函数

    函数对自旋锁进行加锁,如果未能获取到锁,就立刻返回错误,错误码为 EBUSY。

    互斥锁API函数

    1. pthread_mutex_init(pthread_mutex_t*mutex,constpthread_mutexattr_t mutexattr) 初始化函数

    1. Pthread_mutex_lock(pthread_mutex_t *mutex) 加锁函数

    1. Pthread_mutex_unlock(pthread_mutex_t *mutex) 解锁函数

    4、Pthread_mutex_destroy(pthread_mutex_t *mutex) 摧毁锁

    四、自旋锁代码实现

    #include

    #include

    #include

    #include

    #include

    int q_cont;         //计数值

    long loops;         //循环计数次数

    pthread_spinlock_t spin;

    void *task(void *arg)

    {

        long num=(long)arg;

        int j_cont=0;

        int i;

        for(i=0;i

        {

            //加锁

            pthread_spin_lock(&spin);

            

            j_cont=q_cont;

            j_cont++;

            q_cont=j_cont;

            

            //解锁

            pthread_spin_unlock(&spin);

        }

        pthread_exit(NULL);

    }

    int main(int aegc,char *argv[])

    {

        int i;

        pthread_t tid1,tid2;

        loops=atoi(argv[1]);

        

        //初始化自旋锁

        pthread_spin_init(&spin,PTHREAD_PROCESS_PRIVATE);

        //创建线程

        pthread_create(&tid1,NULL,task,(void *)loops);

        pthread_create(&tid2,NULL,task,(void *)loops);

        //等待线程

        pthread_join(tid1,NULL);

        pthread_join(tid2,NULL);

        

        //摧毁锁

        pthread_spin_destroy(&spin);

        printf("q_cont=%d\r\n",q_cont);

        return 0;

    }

    五、互斥锁实现

    #include

    #include

    #include

    #include

    #include

    int q_cont;     //计数值

    long loops;     //计数次数

    pthread_mutex_t lock;

    void *task(void *arg)

    {

        long num=(long)arg;

        int j_cont=0;

        int i;

        for(i=0;i

        {

            //加锁

            pthread_mutex_lock(&lock);

            

            //计数

            j_cont=q_cont;

            j_cont++;

            q_cont=j_cont;

            

            //解锁

            pthread_mutex_unlock(&lock);

        }

        pthread_exit(NULL);

    }

    int main(int aegc,char *argv[])

    {

        int i;

        pthread_t tid1,tid2;

        loops=atoi(argv[1]);

        

        //互斥锁初始化

        pthread_mutex_init(&lock,NULL);

        

        //创建线程      

        pthread_create(&tid1,NULL,task,(void *)loops);

        pthread_create(&tid2,NULL,task,(void *)loops);

        //等待线程结束

        pthread_join(tid1,NULL);

        pthread_join(tid2,NULL);

        //摧毁锁

        pthread_mutex_destroy(&lock);

        

        //打印次数

        printf("q_cont=%d\r\n",q_cont);

        return 0;

    }

    运行结果:

    不加锁:

    加锁后:

    总结:

    将互斥锁替换为自旋锁之后,测试结果打印也是没有问题的,并且通过对比可以发现,替换为自旋锁之后,程序运行所耗费的时间明显变短了,说明自旋锁确实比互斥锁效率要高。

  • 相关阅读:
    2022_08_09__106期__二叉树
    chatgpt配合xmind制作思维导图
    List中的迭代器实现【C++】
    Julia元组、字典、集合
    Serverless Developer Meetup 杭州站精彩回顾!【附赠PPT】
    DVWA-impossible代码审计
    SpringCloud Gateway与Zuul的取舍选择及其工作流程
    第一篇章:JVM与Java体系结构
    基于matlab实现的弹簧振动系统模型程序(动态模型)
    Android OpenGL ES 3.0 FBO 离屏渲染
  • 原文地址:https://blog.csdn.net/weixin_41114301/article/details/126147244