linux设备驱动中的并发控制——信号量

1 信号量
    信号量(semaphore)是用于保护临界区的一种常用方法,他的使用方式与自旋锁类似,只有得到信号量的进程才能 执行临界区代码,与自旋锁不同的是,进程不会原地打转而是进入休眠等待状态。
LINUX系统中与信号量相关的操作主要有如下几种:
1)定义信号量
struct semaphore sem;
2)初始化信号量
void sema_init(struct semphore *sem,int val);//将信号量值设为val
void init_MUTEX(struct semaphore *sem);//初始化一个互斥的信号量,值设为1
void init_MUTEX_LOCKED(struct semaphore *sem);//初始化一个信号量,值为
    此外可以使用如下宏定义和初始化一个信号量(name)
DECLARE_MUTEX(name)
DECLARE_MUTEX_LOCKED(name)//值为0
3)获取信号量
void down(struct semaphore *sem);
    该函数用于获得信号量sem,会导致休眠,因此不能在中断上下文中使用
int down_interruptible(struct semaphore *sem);
    与down()类似,不同在于该函数进入休眠状态的进程能被信号打断,信号也会导致该函数返回,此时该函数的返回值非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);
信号量使用方法如下:
//定义信号量
DECLARE_MUTEX(mount_sem);
down(&mount_sem);
...
critical section//临界区
...
up(&mount_sem);//释放信号量
说明:Linux自旋锁和信号量所采用的"获取锁-访问临界区-释放锁"的方式存在于几乎所有的多任务操作系统中
下列给出了使用信号量实现设备只能被一个进程打开的实例
static DECLARE_MUTEX(xxx_lock);//定义互斥锁
static int xxx_open(struct inode *inode,struct file *filp)
{
...
if(down_trylock(&xxx_lock))//获得打开锁
return -EBUSY;//设备忙
...
return 0;//成功

}
static int xxx_release(struct inode *inode ,structfile *filp)
{
up(&xxx_lock);//释放打开锁
retrun 0;
}

2 信号量用于同步
    如果信号量被初始化为0,则它可用于同步, 同步意味着一个执行单元的继续执行需要等待另一个执行单元完成某事, 保证执行的先后顺序。如图所示,执行单元A执行代码区域b之前,必须等待执行单元B执行完代码单元c,信号量可辅助这一同步过程。
 

linux设备驱动中的并发控制——信号量 - liruibo19830309 - liruibo19830309的博客

                                                图1: 信号量用于同步

3 完成量用于同步
    linux系统提供了一种比信号量更好的同步机制,即完成量,它用于一个执行单元等待另一个执行单元执行完某事。
linux中与completion(完成量)相关的操作有如下四种:
1)定义完成量
struct completion my_completion;
2)初始化完成量
init_completion(&my_completion);
也可以使用下面宏定义和初始化完成量
DECLARE_COMPLETION(my_completion);
3)等待完成量
void wait_completion(struct completion *c);
4)唤醒完成量
void complete(struct completion *c);
void complete_all(struct completion *c);
    前者只唤醒一个等待的执行单元,后者释放所有等待同一完成量的执行单元。下图描述了使用完成量实现的同步功能。

linux设备驱动中的并发控制——信号量 - liruibo19830309 - liruibo19830309的博客

                                                 图2:完成量实现的同步功能

4 读写信号量
    读写信号量可能引起进程堵塞,但它可以允许N个读执行单元同时访问共享资源,而最多只能有一个写执行单元。因此读写信号量是一种相对放宽条件的粒度稍大于信号量的互斥机制。
读写信号量涉及的操作有如下5种
1)定义和初始化读写信号量
struct rw_semphore my_rws;//定义读写信号量
void init_rwsem(struct rw_semphore *my_rws);//初始化读写信号量
2)读信号量获取
void down_read(struct rw_semphore *my_rws);
int down_read_trylock(struct rw_semphore *my_rws);
3)读信号量释放
void up_read(struct rw_semphore *my_rws);
4)写信号量获取
void down_write(struct rw_semphore *my_rws);
int down_write_trylock(struct rw_semphore *my_rws);
5)写信号量释放
void up_write(struct rw_semphore *my_rws);
读写信号量一般这样使用:
rw_sephore rw_sem;
init_rwsem(&rw_sem);
//读时获取信号量
down_read(&rw_sem);
...//临界资源
up_read(&rw_sem);
//写时获取信号量
down_write(&rw_sem);
...//临界资源
up_write(&rw_sem);

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章