并发(二)——linux内核同步机制分析
目录
一、内核产生并发的原因
二、上下文
三、同步
3.1 基本的同步手段
3.1.1 preempt_enable / preempt_disable
3.1.2 local_irq_enable / local_irq_disable
3.1.3 local_bh_enable / local_bh_disable
3.1.4 spin_lock / spin_unlock
3.2 同步手段的组合
四、参考
一、内核产生并发的原因
- 中断 (hardirq, softirq,tasklet)
- 多核
- 内核抢占
必须选用合适的同步手段避免竟态,保护临界区。
二、上下文
- 进程上下文:
- 中断上下文:hardirq上下文,softirq上下文
三、同步
访问临界区时,要分析可能会由哪种并发原因产生静态,从而选择合适的同步手段,可以按照下面的方法分析:
1. 当前访问资源的执行上下文是什么
2. 哪一种或者哪几种并发情况下会产生静态(hardirq/softirq/smp/preempt)
3.1 基本的同步手段
我们先分析单一的原因,在考虑多种并发原因下的同步方法
3.1.1 preempt_enable / preempt_disable
- preempt_enable()/preempt_disable()
一个task 的thread_info结构中有int preempt_count字段,其格式如下,参考【3】:
内核抢占是在中断返回时检查是否可以抢占,通常需要满足两个条件:
1. preempt_count 为0
static __always_inline int preempt_count(void)
{return READ_ONCE(current_thread_info()->preempt_count);
}
当preempt_count为0时允许抢占意味着在hardirq上下文,softirq上下文默认都是不能抢占的
2. thread info中的flag成员是否设定了TIF_NEED_RESCHED
#define tif_need_resched() test_thread_flag(TIF_NEED_RESCHED)static __always_inline bool need_resched(void)
{return unlikely(tif_need_resched());
}
preempt_disable仅仅是将preempt_count的抢占字段+1,那么preempt_count()不为0就无法被抢占了。
在执行上下文仅可能会本cpu线程抢占时,使用该手段
3.1.2 local_irq_enable / local_irq_disable
- local_irq_enable()/local_irq_disable 使能或者关闭本地中断,hardirq
注意,这是针对单个CPU的指令,如在x86上,就是IF bit的置位或清除,使用的情况是有中断和当前执行线程进入临界区
在执行上下文仅可能会被本地hardirq打断时,使用该手段,主要有:
1 .处于进程上下文中的执行线程:被hardirq中断打断访问共享资源
2. 处于softirq上下文中的执行线程,被hardirq 中断打断访问共享资源
那么处于hardirq上下文中的执行线程,可不可能被另一个hardirq打断呢,是可能的,如更高优先级的中断。但是在linux中没有支持同一个hardirq中断嵌套,具体是在发生中断时,硬件都会将本地中断关闭,linux在执行完硬中断处理(即所谓上半部)后,才会打开中断,这时候才会处理另外的中断请求,所以在linux中一个hardirq中断不会打断另一个hardirq,不用考虑关中断
3.1.3 local_bh_enable / local_bh_disable
在执行上下文仅可能会被软中断打断,使用该手段
1. 处于进程上下文中的执行线程:被softirq中断打断访问共享资源
2. 处于softirq上下文中的执行线程,不会被其他softirq抢占
3. 处于hardirq上下文中的执行线程,不会被软中断打断,因为软中断总是在中断处理程序执行完成后才去执行的。
3.1.4 spin_lock / spin_unlock
主要用来保护smp的并发,临界区内不能睡眠!
在执行上下文仅可能会其他cpu访问,使用该手段
spin_lock实现需要关闭抢占,原因是可能在一次中断后,被本地cpu的其他高优先级线程抢占,新线程在进入临界区时spin会导致死锁。
3.2 同步手段的组合
有时候,一个临界区并发访问的原因不只一种,这时候就要将上面的四种同步手段组合,linux中我总结了如下规则:
优先级 hardirq > softirq > preemption,优先级相同时不用考虑并发
这里结合代码分析一下,首先linux在处理中断时,有如下操作:
- __irq_enter : preempt_count_add(HARDIRQ_OFFSET) //此时一定有 preempt_count() != 0,即无法抢占
- 中断处理 //中断上下文
- irq_exit : preempt_count_sub(HARDIRQ_OFFSET); //在这之后才处理softirq、premption,考虑到同种中断不可嵌套,一个hardirq不能被其他hardirq,softirq,preemption打断,优先级最高
继续考虑软中断,在irq_exit时,执行软中断,而在软中断完成,中断返回时,才检查是否需要抢占,值得注意的是,可以抢占的一个条件是不在中断执行环境中,所以如果在软中断上下文被中断打断是不能被其他进程抢占的,具体代码的分析可以参见:中断(二)——linux下半部机制分析
考虑hardirq上下文,softirq上下文,进程上下文:
- 如果是hardirq上下文,不用担心并发(没人抢的过你,且linux不支持同种中断嵌套)
- 如果是softirq上下文,只有hardirq会产生竟态(同级不会)
- 如果是进程上下文,要考虑hardirq和softirq,抢占产生的竟态
此时,再考虑和多核竞争的spin_lock进行组合(注意spin 禁止了抢占):
针对情况1: 无
针对情况2: spin_lock_irq/spin_unlock_irq
针对情况3: spin_lock_irq/spin_unlock_irq
spin_lock_bh/spin_unlock_bh
需要注意的是,一定要仔细分析每一种场景下的并发可能,选取最合适的锁,我总结如下表,理解了无需记忆
并发原因 | hardirq上下文 | software上下文 | 进程上下文 |
preempt | 无需 | 无需 | preempt_disable |
softirq softirq+preempt |
无需 | 无需 | local_bh_disable |
hardirq hardirq + preempt hardirq + softirq |
无需 | local_irq_disable | local_irq_disable |
smp smp + preempt |
spin_lock | spin_lock | spin_lock |
smp + softirq | spin_lock | spin_lock | spin_lock_bh |
smp + hardirq | spin_lock | spin_lock_irq | spin_lock_irq |
四、参考
【1】Linux内核设计与实现 Robert Love
【2】Linux内核同步机制之(四):spin lock
【3】linux kernel的中断子系统之(八):softirq
并发(二)——linux内核同步机制分析相关推荐
- Linux内核同步机制之(四):spin lock【转】
转自:http://www.wowotech.net/kernel_synchronization/spinlock.html 一.前言 在linux kernel的实现中,经常会遇到这样的场景:共享 ...
- Linux内核同步机制之信号量与锁
Linux内核同步控制方法有很多,信号量.锁.原子量.RCU等等,不同的实现方法应用于不同的环境来提高操作系统效率.首先,看看我们最熟悉的两种机制--信号量.锁. 一.信号量 首先还是看看内核中是怎么 ...
- Linux内核poll机制分析
1. poll 机制 本篇主要是进行 poll 内核实现,调用流程的分析. 1.1 sys_poll 分析 应用程序调用 poll() 后,经过 SWI 的处理后,最终会进入内核的 sys_poll( ...
- linux 内核 同步机制
原子操作 原子操作是由编译器来保证的,保证一个线程对数据的操作不会被其他线程打断. 自旋锁 原子操作只能用于临界区只有一个变量的情况,实际应用中,临界区的情况要复杂的多.对于复杂的临界区,L ...
- Linux内核NAPI机制分析
转自:http://blog.chinaunix.net/uid-17150-id-2824051.html 简介: NAPI 是 Linux 上采用的一种提高网络处理效率的技术,它的核心概念就是不采 ...
- Linux内核同步机制之completion
内核编程中常见的一种模式是,在当前线程之外初始化某个活动,然后等待该活动的结束.这个活动可能是,创建一个新的内核线程或者新的用户空间进程.对一个已有进程的某个请求,或者某种类型的硬件动作,等等.在这种 ...
- Linux内核同步机制之(一):原子操作
作者: 郭健 来源: wowotech 一.源由 我们的程序逻辑经常遇到这样的操作序列: 1.读一个位于memory中的变量的值到寄存器中 2.修改该变量的值(也就是修改寄存器中的值) 3.将寄存器中 ...
- linux内核机制是什么,linux内核slab机制分析
1.内部碎片和外部碎片 外部碎片 什么是外部碎片呢?我们通过一个图来解释: image.png 假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框.这个时候,在这段内 ...
- Linux内核同步机制--自旋锁【转】
本文转载自:http://www.cppblog.com/aaxron/archive/2013/04/12/199386.html 自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已 ...
- linux内核同步机制-RCU(3)
在正式开始之前,我们来回顾两个比较重要的概念,grace period和quiescent state. grace period的确定在rcu里很重要,它代表了读操作是否完成,也就是是否退出了临界区 ...
最新文章
- Python培训教程分享:如何实现pygame的初始化和退出操作?
- “计算机之子”winter:我的前端学习路线与方法
- Oracle Execute Plan原理分析与实例分享之一
- Python ord()函数和chr()函数
- 程序员们,您还想熬夜吗?
- 前端学习(1943)vue之电商管理系统电商系统之通过路由加载商品分类
- ParserError: Error tokenizing data. C error: Expected 1 fields in line 122, saw 2
- http://blog.seirsoft.com
- python训练mask rcnn模型C++调用训练好的模型--基于opencv4.0(干货满满)
- linux 反汇编运行时代码段,linux内核学习之一 简单c语言反汇编(示例代码)
- C99标准新特性概览
- 08版新精粹45集实战技巧视频教程免费下载wordExcel
- 解决Ubuntu显卡驱动的问题
- 电磁仿真软件CST2020 下载链接及安装破·解教程笔记
- 优酷动漫押注“新国风”,能否追回被B站、腾讯赶超的那些年?
- 开源聚合支付平台学习
- MySQL 高可用之MMM
- 如何查看电脑的 CPU 信息 ?
- 准确性 敏感性 特异性_特异性图
- Java多态(面试考点,不要因为基础而忽视)
热门文章
- ubuntu 8.10 可用的源
- [导入]如何在标题栏上增加按钮
- cartographer安装_【ROS-SLAM】Cartographer ROS官方文档翻译学习(1)——下载与安装...
- Unity ECS 初探
- spring --(16)AOP前置通知与后置通知
- AJAX学习笔记 一:简单的XMLHTTPRequest示例和asp.net异步更新。
- elasticsearch删除索引
- JProfiler分析内存泄漏
- http访问请求慢的解决思路
- 理解数据库中的undo日志、redo日志、检查点