目录

一、内核产生并发的原因

二、上下文

三、同步

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在处理中断时,有如下操作:

  1. __irq_enter   : preempt_count_add(HARDIRQ_OFFSET)  //此时一定有 preempt_count() != 0,即无法抢占
  2. 中断处理         //中断上下文
  3. irq_exit :         preempt_count_sub(HARDIRQ_OFFSET); //在这之后才处理softirq、premption,考虑到同种中断不可嵌套,一个hardirq不能被其他hardirq,softirq,preemption打断,优先级最高

继续考虑软中断,在irq_exit时,执行软中断,而在软中断完成,中断返回时,才检查是否需要抢占,值得注意的是,可以抢占的一个条件是不在中断执行环境中,所以如果在软中断上下文被中断打断是不能被其他进程抢占的,具体代码的分析可以参见:中断(二)——linux下半部机制分析

考虑hardirq上下文,softirq上下文,进程上下文:

  1. 如果是hardirq上下文,不用担心并发(没人抢的过你,且linux不支持同种中断嵌套)
  2. 如果是softirq上下文,只有hardirq会产生竟态(同级不会)
  3. 如果是进程上下文,要考虑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内核同步机制分析相关推荐

  1. Linux内核同步机制之(四):spin lock【转】

    转自:http://www.wowotech.net/kernel_synchronization/spinlock.html 一.前言 在linux kernel的实现中,经常会遇到这样的场景:共享 ...

  2. Linux内核同步机制之信号量与锁

    Linux内核同步控制方法有很多,信号量.锁.原子量.RCU等等,不同的实现方法应用于不同的环境来提高操作系统效率.首先,看看我们最熟悉的两种机制--信号量.锁. 一.信号量 首先还是看看内核中是怎么 ...

  3. Linux内核poll机制分析

    1. poll 机制 本篇主要是进行 poll 内核实现,调用流程的分析. 1.1 sys_poll 分析 应用程序调用 poll() 后,经过 SWI 的处理后,最终会进入内核的 sys_poll( ...

  4. linux 内核 同步机制

    原子操作   原子操作是由编译器来保证的,保证一个线程对数据的操作不会被其他线程打断.    自旋锁 原子操作只能用于临界区只有一个变量的情况,实际应用中,临界区的情况要复杂的多.对于复杂的临界区,L ...

  5. Linux内核NAPI机制分析

    转自:http://blog.chinaunix.net/uid-17150-id-2824051.html 简介: NAPI 是 Linux 上采用的一种提高网络处理效率的技术,它的核心概念就是不采 ...

  6. Linux内核同步机制之completion

    内核编程中常见的一种模式是,在当前线程之外初始化某个活动,然后等待该活动的结束.这个活动可能是,创建一个新的内核线程或者新的用户空间进程.对一个已有进程的某个请求,或者某种类型的硬件动作,等等.在这种 ...

  7. Linux内核同步机制之(一):原子操作

    作者: 郭健 来源: wowotech 一.源由 我们的程序逻辑经常遇到这样的操作序列: 1.读一个位于memory中的变量的值到寄存器中 2.修改该变量的值(也就是修改寄存器中的值) 3.将寄存器中 ...

  8. linux内核机制是什么,linux内核slab机制分析

    1.内部碎片和外部碎片 外部碎片 什么是外部碎片呢?我们通过一个图来解释: image.png 假设这是一段连续的页框,阴影部分表示已经被使用的页框,现在需要申请一个连续的5个页框.这个时候,在这段内 ...

  9. Linux内核同步机制--自旋锁【转】

    本文转载自:http://www.cppblog.com/aaxron/archive/2013/04/12/199386.html 自旋锁与互斥锁有点类似,只是自旋锁不会引起调用者睡眠,如果自旋锁已 ...

  10. linux内核同步机制-RCU(3)

    在正式开始之前,我们来回顾两个比较重要的概念,grace period和quiescent state. grace period的确定在rcu里很重要,它代表了读操作是否完成,也就是是否退出了临界区 ...

最新文章

  1. Python培训教程分享:如何实现pygame的初始化和退出操作?
  2. “计算机之子”winter:我的前端学习路线与方法
  3. Oracle Execute Plan原理分析与实例分享之一
  4. Python ord()函数和chr()函数
  5. 程序员们,您还想熬夜吗?
  6. 前端学习(1943)vue之电商管理系统电商系统之通过路由加载商品分类
  7. ParserError: Error tokenizing data. C error: Expected 1 fields in line 122, saw 2
  8. http://blog.seirsoft.com
  9. python训练mask rcnn模型C++调用训练好的模型--基于opencv4.0(干货满满)
  10. linux 反汇编运行时代码段,linux内核学习之一 简单c语言反汇编(示例代码)
  11. C99标准新特性概览
  12. 08版新精粹45集实战技巧视频教程免费下载wordExcel
  13. 解决Ubuntu显卡驱动的问题
  14. 电磁仿真软件CST2020 下载链接及安装破·解教程笔记
  15. 优酷动漫押注“新国风”,能否追回被B站、腾讯赶超的那些年?
  16. 开源聚合支付平台学习
  17. MySQL 高可用之MMM
  18. 如何查看电脑的 CPU 信息 ?
  19. 准确性 敏感性 特异性_特异性图
  20. Java多态(面试考点,不要因为基础而忽视)

热门文章

  1. ubuntu 8.10 可用的源
  2. [导入]如何在标题栏上增加按钮
  3. cartographer安装_【ROS-SLAM】Cartographer ROS官方文档翻译学习(1)——下载与安装...
  4. Unity ECS 初探
  5. spring --(16)AOP前置通知与后置通知
  6. AJAX学习笔记 一:简单的XMLHTTPRequest示例和asp.net异步更新。
  7. elasticsearch删除索引
  8. JProfiler分析内存泄漏
  9. http访问请求慢的解决思路
  10. 理解数据库中的undo日志、redo日志、检查点