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

简介: Linux中自旋锁实现的基本原理之经典

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

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

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

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

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

8fa78a64259c44eaad0509fc2390eb02.png

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
int q_cont;     //计数值
long loops;     //计数次数
void *task(void *arg)
{
    long num=(long)arg;
    int j_cont=0;
    int i;
    for(i=0;i<num;i++)  //单线程循环loops次
    {
        //计数
        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) 初始化函数
  2. Pthread_mutex_lock(pthread_mutex_t *mutex) 加锁函数
  3. Pthread_mutex_unlock(pthread_mutex_t *mutex) 解锁函数
  4. Pthread_mutex_destroy(pthread_mutex_t *mutex) 摧毁锁

四、自旋锁代码实现

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
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<num;i++)      //循环loops次
    {
        //加锁
        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<stdio.h>
#include<stdlib.h>
#include<string.h>
#include<unistd.h>
#include<pthread.h>
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<num;i++)  //单线程循环loops次
    {
        //加锁
        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;
}

运行结果:

不加锁:

1b92723479c44305a21575bcfc84106e.png

加锁后:

77e32b952ff0492d81a62385434f86e7.png

总结:

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

目录
相关文章
|
18天前
|
Linux Shell 开发工具
Shell的运行原理以及Linux当中的权限问题
Shell的运行原理以及Linux当中的权限问题
38 0
|
18天前
|
Linux 网络安全 网络虚拟化
Linux虚拟网络设备:底层原理与性能优化深度解析
在深入探讨Linux虚拟网络设备的底层原理之前,重要的是要理解这些设备如何在Linux内核中实现,以及它们如何与操作系统的其他部分交互以提供高效且灵活的网络功能。虚拟网络设备在现代网络架构中发挥着关键作用🔑,特别是在云计算☁️、容器化📦和网络功能虚拟化(NFV)环境中。
Linux虚拟网络设备:底层原理与性能优化深度解析
|
18天前
|
存储 算法 编译器
【Linux 应用开发 】交叉编译的浮点数处理问题:从表象到底层原理的探索与解决
【Linux 应用开发 】交叉编译的浮点数处理问题:从表象到底层原理的探索与解决
45 1
|
18天前
|
存储 Linux API
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用(三)
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用
42 1
|
18天前
|
消息中间件 Linux 数据处理
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用(二)
Linux系统编程 C/C++ 以及Qt 中的零拷贝技术: 从底层原理到高级应用
45 1
|
18天前
|
Cloud Native Linux 网络虚拟化
深入理解Linux veth虚拟网络设备:原理、应用与在容器化架构中的重要性
在Linux网络虚拟化领域,虚拟以太网设备(veth)扮演着至关重要的角色🌐。veth是一种特殊类型的网络设备,它在Linux内核中以成对的形式存在,允许两个网络命名空间之间的通信🔗。这篇文章将从多个维度深入分析veth的概念、作用、重要性,以及在容器和云原生环境中的应用📚。
深入理解Linux veth虚拟网络设备:原理、应用与在容器化架构中的重要性
|
11天前
|
Shell Linux 程序员
【Linux】Shell 命令以及运行原理
【Linux】Shell 命令以及运行原理
|
18天前
|
存储 Linux 程序员
【操作系统原理】—— Linux内存管理
【操作系统原理】—— Linux内存管理
|
18天前
|
Unix Linux
|
18天前
|
Linux Shell 程序员
【Linux】权限(shell运行原理、概念,Linux权限)
【Linux】权限(shell运行原理、概念,Linux权限)
20 2