Linux 设备驱动的并发控制

       Linux 设备驱动中必须要解决的一个问题是多个进程对共享的资源的并发访问,并发的访问会导致竞态,即使是经验丰富的驱动工程师也常常设计出包含并发问题bug 的驱动程序。


一、基础概念

1、Linux 并发相关基础概念

a -- 并发(concurrency):并发指的是多个执行单元同时、并发被执行,而并发的执行单元对共享资源(硬件资源和软件上的全局变量、静态变量等)的访问则很容易导致竞态(race condition);

b -- 竞态(race condition) :竞态简单的说就是两个或两个以上的进程同时访问一个资源,同时引起资源的错误;

c -- 临界区(Critical Section):每个进程中访问临界资源的那段代码称为临界区

d -- 临界资源 :一次仅允许一个进程使用的资源称为临界资源;多道程序系统中存在许多进程,它们共享各种资源,然而有很多资源一次只能供一个进程使用;


      在宏观上并行或者真正意义上的并行(这里为什么是宏观意义的并行呢?我们应该知道“时间片”这个概念,微观上还是串行的,所以这里称为宏观上的并行),可能会导致竞争; 类似两条十字交叉的道路上运行的车。当他们同一时刻要经过共同的资源(交叉点)的时候,如果没有交通信号灯,就可能出现混乱。在linux 系统中也有可能存在这种情况:

2、并发产生的场合

a -- 对称多处理器(SMP)的多个CPU

       SMP 是一种共享存储的系统模型,它的特点是多个CPU使用共同的系统总线,因此可访问共同的外设和储存器,这里可以实现真正的并行

b -- 单CPU内进程与抢占它的进程

       一个进程在内核执行的时候有可能被另一个高优先级进程打断;

c -- 中断和进程之间

       中断可以打断正在执行的进程,如果中断处理函数程序访问进程正在访问的资源,则竞态也会发生;


3、解决竞态问题的途径

      解决竞态问题的途径最重要的是保证对共享资源的互斥访问,所谓互斥访问是指一个执行单元在访问共享资源的时候,其他的执行单元被禁止访问。

      Linux 设备中提供了可采用的互斥途径来避免这种竞争。主要有原子操作信号量自旋锁

     那么这三种有什么相同的地方,有什么区别呢?适用什么不同的场合呢?会带来什么边际效应?要彻底弄清楚这些问题,要从其所处的环境来进行细化分类处理。是UP(单CPU)还是SMP(多CPU);是抢占式内核还是非抢占式内核;是在中断上下文不是进程上下文。似交通信号灯一样的措施来避免这种竞争。

    先看一下三种并发机制的简单概念:

 原子锁:原子操作不可能被其他的任务给调开,一切(包括中断),针对单个变量

 自旋锁:使用忙等待锁来确保互斥锁的一种特别方法,针对是临界区

 信号量:包括一个变量及对它进行的两个原语操作,此变量就称之为信号量,针对是临界区



二、并发处理途径详解

1、中断屏蔽

      在单CPU范围内避免静态的一种简单而省事的方法是在进入临界区之前屏蔽系统的中断,这项功能可以保证正在执行的内核执行路径不被中断处理程序所抢占,防止某些竞争条件的发生。具体而言

a -- 中断屏蔽将使得中断和进程之间的并发不再发生

b -- 由于Linux内核的进程调度等操作都依赖中断来实现内核抢占进程之间的并发也得以避免

中断屏蔽的使用方法:

    local_irq_disable()
    local_irq_enable()
只能禁止和使能本地CPU的中断,所以不能解决多CPU引发的竞态

    local_irq_save(flags)
    local_irq_restore(flags)
除了能禁止和使能中断外,还保存和还原目前的CPU中断位信息

    local_bh_disable()
    local_bh_disable()
如果只是想禁止中断的底半部,这是个不错的选择。

但是要注意:

a -- 中断对系统正常运行很重要,长时间屏蔽很危险,有可能造成数据丢失乃至系统崩溃,所以中断屏蔽后应尽可能快的执行完毕。

b -- 宜与自旋锁联合使用。

       所以,不建议使用中断屏蔽


2、原子操作

      原子操作(分为原子整型操作和原子位操作)就是绝不会在执行完毕前被任何其他任务和时间打断,不会执行一半,又去执行其他代码原子操作需要硬件的支持,因此是架构相关的,其API和原子类型的定义都在include/asm/atomic.h中,使用汇编语言实现。

  在linux中,原子变量的定义如下:

    typedef struct {
        volatile int counter;
    } atomic_t;

    关键字volat

  • 8
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
Linux设备驱动中,由于多个进程或线程可能会同时访问设备,因此需要进行并发控制以确保设备的正确性和稳定性。以下是一些常用的Linux设备驱动中的并发控制方法: 1. 互斥锁(mutex):互斥锁是用于保护临界区的一种机制,当一个进程或线程进入临界区时,其他进程或线程必须等待其退出后才能进入。Linux内核提供了多种不同类型的互斥锁,如spinlock、semaphore等,开发者可以根据实际需求选择不同的锁类型。 2. 读写锁(rwlock):读写锁是一种特殊的互斥锁,它允许同时有多个读者访问共享资源,但只允许一个写者访问。读写锁可以提高并发性能,但也需要考虑读写锁的开销。 3. 自旋锁(spinlock):自旋锁是一种忙等待的锁,当一个进程或线程无法获取锁时,它会一直循环尝试获取锁,直到获取成功。自旋锁对于短时间的临界区保护非常有效,但长时间的自旋会浪费CPU资源。 4. 原子操作(atomic):原子操作是一种不可分割的操作,可以保证操作的完整性和一致性。在Linux设备驱动中,原子操作通常用于对共享变量的操作,如增减计数器等。 除了以上方法,还有一些高级的并发控制技术,如RCU、信号量(semaphore)等,它们可以根据具体的应用场景来选择使用。在开发Linux设备驱动时,需要根据实际情况选择合适的并发控制方法,并注意避免死锁和竞争条件等问题。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值