【精通内核】Linux内核自旋锁实现原理与源码解析_linux自旋锁底层实现原理

本文详细介绍了Linux内核中的自旋锁和读写锁的工作原理,包括自旋锁的实现机制、获取和释放过程,以及在多处理器环境下的应用。同时提供了Linux内核源码的实例分析。
摘要由CSDN通过智能技术生成

📫作者简介:小明java问道之路,专注于研究计算机底层/Java/Liunx 内核,就职于大型金融公司后端高级工程师,擅长交易领域的高安全/可用/并发/性能的架构设计📫

🏆 CSDN专家博主/Java优质创作者/CSDN内容合伙人、InfoQ签约作者、阿里云签约专家博主、华为云专家、51CTO专家/TOP红人 🏆

🔥如果此文还不错的话,还请👍关注、点赞、收藏三连支持👍一下博主~

本文目录

本文导读

一、Linux内核自旋锁原理

二、Linux内核源码实现

三、Linux内核自旋读写锁源码解析

1、Linux内核自旋锁读锁

2、Linux内核自旋锁写锁

总结


本文导读

对于一些数据结构,例如阻塞队列来说本身队列就是非线程安全,所以我们就需要实现同步的需求(信号量),这时就需要自旋锁这种机制,同时自旋锁也是与 CPU 核数相关的,下面我们了解其内核源码实现。

一、Linux内核自旋锁原理

前面我们看到了自旋锁的使用,因为对于一些结构,例如线程阻塞队列来说,本身队列就是非程安全的,而我们又需要通过该队列来实现其他的同步结构,如信号量,这时就需要自旋锁来提供种机制,同时读者应注意,在单核 CPU 中不需要使用自旋锁,而在 MP 对多处理器中才需使用它,也就是说单核 CPU 不需要自旋锁。下面直接查看源码实现。

自旋锁结构体 
typedef struct {
    // 自旋锁为无符号的volatile 整型变量 
    volatile unsigned int lock;
}spinlock_t;

// 宏定义创建一个值为1的自旋锁
#define SPIN_LOCK_UNLOCKED(spinlock_()(1}

// 宏定义自旋锁初始化
#define spin_lock_init(x) 
do {
    *(x) = SPIN_LOCK_UNLOCKED;
} while(0)

//  宏定义判断自旋锁是否被锁定,通过将 lock 变量转为 volatile signed char 看看是否小于或等于0
#define spin_is_locked(x) (*(volatile signed char *)(&(x)->lock) <= 0)

// 宏定义等待自旋锁释放,这里的 barrier()为前述内容曾讨论过的编译器屏障
#define spin_unlock_wait(x) 
do{
    barrier();
} while(spin_is_locked(x))

二、Linux内核源码实现

自旋锁就是一个无符号整型值的 lock 变量,通过 volatile 的修饰,可以让它避免被编译器优化。接下来,查看获取自旋锁的代码实现。

// 宏定义获取自旋锁内联汇编代码
#define spin_lock_string
    "1:"
    "lock ; decb %0"  // 对lock 变量自减	
    "js 2f"	          // 如果小于O,则跳转到前面标号2处	
    LOCK_SECTION_START("")
    "2:"
    "rep;nop"	    // 执行空操作	
    "cmpb $0, %0"	// 比较lock的值是否为0	
    "jle 2b"	    // 如果非 0,则继续跳到标号2处循环判断	
    "jmp 1b"	    // 如果等于0,则跳到标号1处重新开始尝试获取锁	
    LOCK_SECTION_END

// 直接上锁,如果上锁失败,则进入前面的 spin_lock_string中,自旋等待 
static inline void_raw_spin_lock(spinlock_t *lock) {
    __asm___volatile__(
        spin_lock_string
        :"=m" (lock->lock): : "memory");
}

// 下面为自旋锁释放锁的代码实现。
#define spin_unlock_string
    "movb $1,%0"	// 将立即数 1 设置为 lock的值	
        :"=m" (lock->lock)::"memory"

static inline void_raw_spin_unlock(spinlock_t *lock) {
    __asm___volatile__(
        spin_unlock_string);
}

三、Linux内核自旋读写锁源码解析

从上述内容中可以看到,自旋锁在 Linx 中的实现就是不停地对 lock 变量的减 1,然后在循环等待它变为1时,再次尝试获取锁;而释放锁较为简单,只需要将其设置为!即可。我们知道在读存在的情况下,使用同一把锁会导致粒度较大,这时通常将其实现为读写锁,同样,内核中也存在一个读写自旋锁。现在查看它的实现原理。

// 上述的自旋锁都是互斥自旋锁,这里定义了一个读写自旋锁,即支持多个读共享,写者互斥 
typedef struct{
    volatile unsigned int lock;
}rwlock_t;   // 和互斥自旋锁一样的结构

// 宏定义获得一个初始化的读写自旋锁
#define RW_LOCK UNLOCKED(rwlock_t){RWLOCKBIAS}
// 宏定义RW_LOCK_BIAS 为0x0100 0000。我们以int 类型的lock的第7位作为写锁标志位

// 宏定义初始化的读写自旋锁
#define rwlock_init(x)	
do { 
    *(x) = RW_LOCK_UNLOCKED; 
} while(0)	

// 宏定义判断读写自旋锁是否上锁了,也就是说看看lock是否为RW_LOCK_BIAS
#define rwlock_is_locked(x) ((x)->lock != RW LOCK_BIAS)

1、Linux内核自旋锁读锁

// 获取读锁
static inline void_raw_read_lock(rwlock_t*rw){
    __build_read_lock(rw, "___read_lock_failed");


### 最后的话

最近很多小伙伴找我要Linux学习资料,于是我翻箱倒柜,整理了一些优质资源,涵盖视频、电子书、PPT等共享给大家!

### 资料预览

给大家整理的视频资料:

![](https://img-blog.csdnimg.cn/img_convert/eeb5e0086f47af9853c10199c3565d2c.png)

给大家整理的电子书资料:

  

![](https://img-blog.csdnimg.cn/img_convert/fcb5abc0d2aa16b18161c5e854a9282f.png)



**如果本文对你有帮助,欢迎点赞、收藏、转发给朋友,让我有持续创作的动力!**

**网上学习资料一大堆,但如果学到的知识不成体系,遇到问题时只是浅尝辄止,不再深入研究,那么很难做到真正的技术提升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
升。**

**[需要这份系统化的资料的朋友,可以点击这里获取!](https://bbs.csdn.net/topics/618542503)**


**一个人可以走的很快,但一群人才能走的更远!不论你是正从事IT行业的老鸟或是对IT行业感兴趣的新人,都欢迎加入我们的的圈子(技术交流、学习资源、职场吐槽、大厂内推、面试辅导),让我们一起学习成长!**
  • 3
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值