再解析下内核自旋锁和优先级翻转问题

[内核同步]自旋锁spin_lock、spin_lock_irq 和 spin_lock_irqsave 分析

漫画|Linux 并发、竞态、互斥锁、自旋锁、信号量都是什么鬼?

Linux内核自旋锁

之前写的自旋锁的文章,现在再加一篇,可能单纯的一两次说明不能把问题说清楚。所以再写一篇文章,也希望更多的人参与讨论,这样会让问题更加清晰明了。

自旋锁的特点是在等待锁的过程中不会休眠,会不断的占用CPU轮询锁的状态,一旦发现锁被释放,就会马上获取锁。 基于这样的特点,自旋锁spinlock适用于保护执行时间非常短的临界区。

自旋锁有两个特点

  • 进入临界区后不能调用可能引起系统休眠的函数。

  • 临界区的代码不能被中断函数重入调用。

如果进入临界区后睡眠,会引起这样的问题,如下图

如果临界区的代码在执行的时候,中断重入调用,如下图

上面两种情况下,都出现一个问题,就是在临界区运行时,还没有来得及释放锁,当前进程被动释放了CPU的使用权,然后下次「可能是中断处理函数,可能是CPU调度的其他进程」再进来的时候,情况就会比较复杂,因为之前的程序一直没有释放,导致锁一直获取失败,失败后又一直在等待,而且永远等不到锁的释放,就会导致死锁了。

优先级反转问题

系统运行对时间要求非常严格,如果因为某些问题导致系统时间延迟有误差,可能会导致比较严重的问题,这种情况在实时系统中会更严重。

我描述下优先级反转的问题。

A和C共享一个资源,但是在运行过程中,在某一个时刻,C占有资源的时候,被高于它优先级的进程B抢占了,这时候B就处于一个有利位置,一直会有CPU运行,如果有其他进程优先级高于C的,也会能拿到CPU运行。

这就出现了一个奇怪的现象,低优先级的进程抢占了高优先级的进程,如果A是特斯拉的刹车进程的话,我相信故障就此发生。

如何解决优先级翻转的问题呢?

  • 提升C的优先级,让C的优先级高于B,就不会存在持有锁的情况下被抢占。

但是C的优先级提升到多少合适呢?

假设共享资源R,有5个任务会申请它,我们需要做的是,持有R资源的任务的优先级是这5个任务中最高的,这就叫优先级提升

spinlock相关代码,基于4.4内核

typedef struct {volatile unsigned int slock;
} arch_spinlock_t;#define __ARCH_SPIN_LOCK_UNLOCKED__ 0
#define __ARCH_SPIN_LOCK_LOCKED__ 1#define __ARCH_SPIN_LOCK_UNLOCKED { __ARCH_SPIN_LOCK_UNLOCKED__ }
#define __ARCH_SPIN_LOCK_LOCKED  { __ARCH_SPIN_LOCK_LOCKED__ }
//...typedef struct raw_spinlock {arch_spinlock_t raw_lock;
#ifdef CONFIG_GENERIC_LOCKBREAKunsigned int break_lock;
#endif
#ifdef CONFIG_DEBUG_SPINLOCKunsigned int magic, owner_cpu;void *owner;
#endif
#ifdef CONFIG_DEBUG_LOCK_ALLOCstruct lockdep_map dep_map;
#endif
} raw_spinlock_t;//...typedef struct spinlock {union {struct raw_spinlock rlock;#ifdef CONFIG_DEBUG_LOCK_ALLOC
# define LOCK_PADSIZE (offsetof(struct raw_spinlock, dep_map))struct {u8 __padding[LOCK_PADSIZE];struct lockdep_map dep_map;};
#endif};
} spinlock_t;

自旋锁函数调用

static __always_inline void spin_lock(spinlock_t *lock)
{raw_spin_lock(&lock->rlock);
}
//1==================
#define raw_spin_lock(lock) _raw_spin_lock(lock)
//2==================
#ifndef CONFIG_INLINE_SPIN_LOCK
void __lockfunc _raw_spin_lock(raw_spinlock_t *lock)
{__raw_spin_lock(lock);
}
EXPORT_SYMBOL(_raw_spin_lock);
#endif
//3==================
static inline void __raw_spin_lock(raw_spinlock_t *lock)
{preempt_disable();spin_acquire(&lock->dep_map, 0, 0, _RET_IP_);LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
}
//4==================LOCK_CONTENDED(lock, do_raw_spin_trylock, do_raw_spin_lock);
//5==================
#define LOCK_CONTENDED(_lock, try, lock)   \
do {        \if (!try(_lock)) {     \lock_contended(&(_lock)->dep_map, _RET_IP_); \lock(_lock);     \}       \lock_acquired(&(_lock)->dep_map, _RET_IP_);   \
} while (0)//6==================
static inline void do_raw_spin_lock(raw_spinlock_t *lock) __acquires(lock)
{__acquire(lock);arch_spin_lock(&lock->raw_lock);
}//7==================static inline void arch_spin_lock(arch_spinlock_t *lock)
{unsigned int val;SCOND_FAIL_RETRY_VAR_DEF;smp_mb();__asm__ __volatile__("0: mov %[delay], 1  \n""1: llock %[val], [%[slock]] \n" /*LOCK指令前缀会设置处理器的LOCK#信号(译注:这个信号会使总线锁定,阻止其他处理器接管总线访问内存),直到使用LOCK前缀的指令执行结束,这会使这条指令的执行变为原子操作。在多处理器环境下,设置LOCK#信号能保证某个处理器对共享内存的独占使用。*/" breq %[val], %[LOCKED], 0b \n" /* spin while LOCKED 判断变量是否为0,如果不为0,说明自旋锁已经被获取,当前获取就会失败 */" scond %[LOCKED], [%[slock]] \n" /* acquire */" bz 4f   \n" /* done */"     \n"SCOND_FAIL_RETRY_ASM: [val]  "=&r" (val)SCOND_FAIL_RETRY_VARS: [slock] "r" (&(lock->slock)),[LOCKED] "r" (__ARCH_SPIN_LOCK_LOCKED__) /*获取锁,把变量值加1*/: "memory", "cc");smp_mb();
}

参考

  • https://blog.csdn.net/longwang155069/article/details/52055876


推荐阅读:

专辑|Linux文章汇总

专辑|程序人生

专辑|C语言

我的知识小密圈

关注公众号,后台回复「1024」获取学习资料网盘链接。

欢迎点赞,关注,转发,在看,您的每一次鼓励,我都将铭记于心~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/466043.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ios 逆向编程(环境搭建)

首先如果你想要逆向其他的APP 动态的查看 或者修改人家APP里面的东西 1, 首先要有一台越狱的手机 最好是9.1以下的,因为9.2以上(包括9.2)就不能完美越狱了 2,手机也要5s以上的(因为从5S开始支持arm64架构&…

最大、最小堆的实现

最大最小堆 堆是一种经过排序的完全二叉树,其中任一非终端节点的数据值均不大于(或不小于)其左子节点和右子节点的值。 最大堆和最小堆是二叉堆的两种形式。 最大堆:根结点的键值是所有堆结点键值中最大者。 最小堆:根…

嵌入式OS入门笔记-以RTX为案例:四.简单的时间管理

嵌入式OS入门笔记-以RTX为案例:四.简单的时间管理 上一节简单记录了进程task。有了进程以后,我们需要关心怎么样分配CPU资源(或者运行时间)给每个进程。那么就要引入排程(scheduling)的概念。排程一般都是O…

我等这个含蓄的技术男当上了CEO

大家好,祝大家五一节日快乐!今天没有写技术文章,今天想吹一个人,他是我的朋友,他做公众号很久了,技术文章写的也不错,但是阅读和关注量一直没有上来,我之前好几次在公众号上转发了他…

广东总冠军

lets go tiger 看这篇文章之前,先看看我们看球的视频 恭喜广东拿下总冠军! 恭喜胡明轩夺得FMVP! 我当时预测的是周鹏或者胡明轩拿下FMVP,最后是胡明轩,广东后场三条枪表现都非常亮眼。如果是上一场广东夺冠&#xff0c…

每日一题(1) —— 数组计算

判断下面代码是否可执行&#xff1f;如果可执行&#xff0c;执行结果是多少&#xff1f; #include <stdio.h>int main(void) {int array[10] {0, 2, 3, 4, 5, 6, 7, 8, 9, 10};0[array] 1;printf("%d\n", (-1)[array 5]);return 0; } 分析&#xff1a; C语…

内存文章汇总,并剖析mmap

在看这篇文章之前&#xff0c;可以先看看下面这几篇文章Linux内存&#xff0c;先看这篇文章Linux内存寻址方式Linux虚拟内存TLBLinux物理内存初始化Linux io内存存在的意义~修改cmdline 把内存改成512MB用mtrace定位内存泄漏什么是内存泄漏&#xff1f;Linux内存管理slub分配器…

[综述泛读] A survey on web services composition (IJWGS, 2005)

Time: 2.5 hours Dustdar S, Schreiner W. "A survey on web services composition." International Journal of Web and Grid Services: 1-30. 2005 (30 pages, 单栏) (gs:169) Schahram Dustdar (维也纳技术大学, full prof) Dusdar是Distributed Systems Group的老…

韦老师的开发板和嵌入式书籍赠送

大家五一快乐&#xff01;我知道这个时候大家都没有什么心思学习&#xff0c;所以找了联合了几个朋友一起给大家送点东西。这几个技术号主都非常用心的给大家分享技术文章&#xff0c;我相信&#xff0c;跟他们一起&#xff0c;你们也能变得更加优秀。奖品包括&#xff1a;1. 韦…

每日一题(2)—— -2与2的比较

分析下面的代码&#xff0c;求运行结果。 #include <stdio.h>int main(void) {if(-2 > 2){printf("11111\r\n");}else{printf("22222\r\n");}return 0; }分析&#xff1a; -2和2都没有声明存储类型&#xff0c;编译器默认按int存储&#xff0c;所…

truffle unbox react 出坑指南

最近几天差点就被这鬼东西给逼疯了&#xff0c;truffle init 、truffle unbox webpack 不管我怎么运行都是对的&#xff0c;唯独truffle unbox react 不管在哪个windows都会报错&#xff0c;换了好几台电脑&#xff0c;心都累完了&#xff0c;还好我坚持了下来&#xff0c;找了…

单片机6年想转嵌入式Linux ,不知如何下手?

刷知乎看到下面这个提问。单片机6年想转嵌入式Linux &#xff0c;不知如何下手&#xff1f;现在挺尴尬&#xff0c;做的单片机产品总是感觉重复重复再重复&#xff0c;想学习点新东西&#xff0c;不知道如何转。说实话&#xff0c;这个问题自己关注了很久。今天就借题主这个问题…

每日一题(3)—— -2与2的比较(二)

分析下面的代码&#xff0c;求运行结果。 #include <stdio.h>int main(void) {if(-2L > 2UL){printf("11111\r\n");}else{printf("22222\r\n");}return 0; }分析&#xff1a; 常量后面接L表示long型存储&#xff0c;UL表示unsigned long型存储&a…

嵌入式技术面试时的10大潜规则

编排 | strongerHuang微信公众号 | 嵌入式专栏找工作也是一门技能&#xff0c;有的人很快就找到自己喜欢的工作&#xff0c;有的人找了很久也没找到合适的工作。下面给大家分享几点找工作过程中存在的“潜规则”内容。嵌入式专栏1面试的本质不是考试&#xff0c;而是告诉面试官…

每日一题(4)—— (a ^ b 2)

分析下面的代码&#xff0c;求运算结果。 #include <stdio.h>int main(void) {int a 6, b 4;printf("%d\n", a ^ b << 2);return 0; }分析&#xff1a; 主要是考的是“优先级”和按位“异或”&#xff0c; 左移运算符优先级高于按位异或运算符&#…

轻轻的你来了,悄悄的你走了,邓总没有带走一个bug

写这篇文章的时候&#xff0c;比较晚&#xff0c;所以思绪是清晰的&#xff0c;这个时候刚好是邓总来公司跟我交接离职的最后一天。给邓总制作的告别MV&#xff1a;我跟邓总2017年12月在恒大认识&#xff0c;我们入职时间相差一周&#xff0c;我入职的时候就开始注意到旁边的这…

神奇的css3(2)动画

四、Css3 2D动画 1、2D 转换方法 函数 描述 matrix(n,n,n,n,n,n) 定义 2D 转换&#xff0c;使用六个值的矩阵。 translate(x,y) 定义 2D 转换&#xff0c;沿着 X 和 Y 轴移动元素。 translateX(n) 定义 2D 转换&#xff0c;沿着 X 轴移动元素。 translateY(n) 定义 2D…

固定宽度弹性布局(以适应各种各辨率)

最佳网页宽度及其实现——新手可了解一下 1.设计网页的时候&#xff0c;确定宽度是一件很苦恼的事。以minifun.cn为例&#xff0c;根据Google Analytics的统计&#xff0c;半年多以来&#xff0c;访问者的屏幕分辨率一共有81种。最小的分辨率是122x160&#xff0c;这应该是手机…

B站这套教程火了,火速搬运!限时删除~

最近好多粉丝给我留言&#xff0c;寻求人工智能入坑资源&#xff0c;想利用人工智能来实现一些大胆的想法、项目或创意&#xff0c;或是想进入AI行业搞钱。不过细聊之下&#xff0c;大部分伙伴苦于不知从何入手&#xff0c;找不到重点。更甚至被烧脑的算法劝退&#xff0c;折腾…

【MySQL学习笔记008】多表查询

1、多表关系 概述&#xff1a;项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表结构之间也存在着各种联系&#xff0c;基本上可分为三种&a…