Linux内核同步方法之自旋锁


前言

软硬件环境
硬件: PC
软件:ubuntu18.04

本文主要介绍linux 内核同步方法中的自旋锁, 它是一种轻量级的锁,和原子操作,互斥锁,信号量等内核同步方法的作用相同,都是为了保护临界区。自旋锁在内核中主要是用来防止多处理器(SMP)中并发访问临界区,防止内核抢占造成的竞争。

Linux内核是一种抢占式内核。

一、什么是自旋锁

1. 自旋锁的含义

自旋锁( spin lock)是一种典型的对临界资源进行互斥访问的手段,其名称来源于它的工作方式。当锁被某个线程持有后,有其他线程试图再次执行加锁操作的时候,所有这些试图获取锁的线程不会阻塞,而是处于循环等待的忙等状态(CPU不能够做其他事情),直到锁重新可用。
自旋锁主要针对 SMP 或单 CPU 但内核可抢占的情况,对于单 CPU 和内核不支持抢占的系统, 自旋锁退化为空操作,自旋锁最基础的功能就是禁止内核抢占。

2. 单处理器的自旋锁

  1. 如果系统不支持内核抢占,自旋锁的实现是空的,因为单核只有一个线程在执行,不会有内核抢占,从而资源也不会被其他线程访问到;
  2. 如果系统支持内核抢占,由于自旋锁是禁止抢占内核的,所以不会有其他的进程因为等待锁而自旋;

3. 多处理器(SMP)的自旋锁

  1. Linux内核是一种抢占式内核,在多cpu下,由于自旋锁是禁止抢占内核的,其他的cpu因为等待该cpu释放锁,而处于自旋状态,不停轮询锁的状态。所以这样的话,如果一旦自旋锁内代码执行时间较长,等待该锁的cpu会耗费大量资源,也是不同于信号量和互斥锁的地方。

二、自旋锁及其衍生型

尽管用了自旋锁可以保证临界区不受别的 CPU 和本 CPU 内的抢占进程打扰,但是得到锁的代码在执行临界区的时候,还可能受到中断和底半部( BH)的影响。为了防止这种影响,就需要用到自旋锁 (spin_lock()/spin_unlock()是自旋锁机制的基础) 的衍生型, 下图是基础型自旋锁及其最常用的两种衍生型的接口描述。

函数(方法) 描述
spin_lock() 获取指定的自旋锁
spin_lock_irq() 先禁止本地中断然后获取指定的自旋锁
spin_lock_irqsave() 先保存本地中断的当前状态,之后禁止本地中断并获取指定的自旋锁
spin_unlock() 释放指定的自旋锁
spin_unlock_irq() 释放指定的自旋锁,并激活本地中断
spin_unlock_irqrestore() 释放指定的自旋锁,并让本地中断恢复到之前的状态

以上三种形式的自旋锁,需根据实际情况来选用, 一般在SMP的Linux内核中spin_lock_irqsave()/spin_unlock_irqrestroe()用的最多,特别是在中断处理函数中。

三、自旋锁的使用实例

自旋锁一般这样被使用:

spinlock_t lock; //定义自旋锁
spin_lock_init(&lock); //初始化自旋锁
spin_lock (&lock) ; //获取自旋锁,保护临界区
//临界区代码
spin_unlock (&lock) ; //解锁

1. spin_lock()/spin_unlock()

如下图所示,是一个最简的spin_lock()/spin_unlock()使用实例

#include <linux/init.h>
#include <linux/module.h>

#include <linux/slab.h>                          //kzalloc 头文件
#include <linux/spinlock.h>                      //spinlock 头文件

struct spin_test {
   
    int num;          // data
    spinlock_t lock;  // spin lock
};


struct spin_test *s_test = NULL;

static int hello_init(void)
{
   
    printk(KERN_INFO "in hello init\n");
    s_test = kzalloc(sizeof(struct spin_test), GFP_KERNEL);
    if ( s_test == NULL) {
   
        printk(KERN_INFO "kzalloc failed\n");
        return -ENOMEM;
    }

    spin_lock_init(&s_test->lock);                        //spin_lock init   初始化自旋锁

    spin_lock(&s_test->lock);                       
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值