Linux设备驱动中的并发控制---信号量

Linux 设备驱动中必须解决的一个问题是多个进程对共享资源的并发访问,并发访问会导致竞态。 

1、并发与竞态

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

在Linux内核中,主要的竞态发生于如下几种情况:

(1)、对称多处理器(SMP)的多个CPU 

(2)、 CPU 内进程与抢占它的进程

(3)、中断(硬中断、软中断、Tasklet、底半部)与进程之间 

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

访问共享资源的代码区域称为临界区(critical  sections) ,临界区需要以某种互斥机制加以保护。中断屏蔽、原子操作、自旋锁和信号量等是 Linux 设备驱动中可采用的互斥途径。 

2、信号量的使用

信号量(semaphore)是用于保护临界区的一种常用方法,它的使用方式和自旋锁类似。与自旋锁相同,只有得到信号量的进程才能执行临界区代码。但是,与自旋锁不同的是,当获取不到信号量时,进程不会原地打转而是进入休眠等待状态。 

Linux系统中与信号量相关的操作主要有如下 4 种。 

1.定义信号量 

下列代码定义名称为sem的信号量。 
struct semaphore sem;  

2.初始化信号量 

void sema_init (struct semaphore *sem, int val); 
该函数初始化信号量,并设置信号量 sem 的值为 val。尽管信号量可以被初始化为大于1的值从而成为一个计数信号量,但是它通常不被这样使用。 

void init_MUTEX(struct semaphore *sem); 
该函数用于初始化一个用于互斥的信号量,它把信号量 sem 的值设置为 1,等同于sema_init (struct semaphore *sem, 1)。 

void init_MUTEX_LOCKED (struct semaphore *sem); 

该函数也用于初始化一个信号量,但它把信号量 sem 的值设置为 0,等同于sema_init (struct semaphore *sem, 0)。 

此外,下面两个宏是定义并初始化信号量的“快捷方式” 。 
DECLARE_MUTEX(name)  
DECLARE_MUTEX_LOCKED(name) 
前者定义一个名为 name 的信号量并初始化为1,后者定义一个名为 name 的信号量并初始化为0。 

3.获得信号量 

void down(struct semaphore * sem); 
该函数用于获得信号量sem,它会导致睡眠,因此不能在中断上下文使用。 

int down_interruptible(struct semaphore * sem);  
该函数功能与 down()类似,不同之处为,因为down()而进入睡眠状态的进程不能被信号打断,而因为 down_interruptible()而进入睡眠状态的进程能被信号打断,信号
也会导致该函数返回,这时候函数的返回值非0。 

int down_trylock(struct semaphore * sem); 
该函数尝试获得信号量 sem,如果能够立刻获得,它就获得该信号量并返回 0,否则,返回非0值。它不会导致调用者睡眠,可以在中断上下文使用。 

在使用down_interruptible()获取信号量时,对返回值一般会进行检查,如果非 0,通常立即返回-ERESTARTSYS,如: 

if (down_interruptible(&sem)) 

return  - ERESTARTSYS; 

4.释放信号量 

void up(struct semaphore * sem); 
该函数释放信号量 sem,唤醒等待者。 

信号量一般这样被使用,如下所示: 

//定义信号量 
DECLARE_MUTEX(mount_sem); 
down(&mount_sem);//获取信号量,保护临界区 
... 
critical section //临界区 
... 
up(&mount_sem);//释放信号量 

如下代码 给出了使用信号量实现设备只能被一个进程打开的例子:

1  static DECLARE_MUTEX(xxx_lock);//定义互斥锁 
2  
3  static int xxx_open(struct inode *inode, struct file *filp) 
4  { 
5    ... 
6    if (down_trylock(&xxx_lock))  //获得打开锁 
7        return  - EBUSY;  //设备忙 
8    ...   
9    return 0; /* 成功 */ 
10 } 
11  
12 static int xxx_release(struct inode *inode, struct file *filp) 
13 { 
14   up(&xxx_lock);  //释放打开锁 
15   return 0; 
16 } 
 

以上来自《LInux设备驱动开发详解》对于使用到的内容以后在进步以完善

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值