当前位置:嗨网首页>书籍在线阅读

13-信号量的使用

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

7.5.1 信号量的使用

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

Linux中与信号量相关的操作主要有:

1.定义信号量

下列代码定义名称为sem的信号量:

struct semaphore sem;

2.初始化信号量

void sema_init(struct semaphore *sem, int val);

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

define init_MUTEX(sem) sema_init(sem, 1)

该宏用于初始化一个用于互斥的信号量,它把信号量sem的值设置为1;

define init_MUTEX_LOCKED(sem) sema_init(sem, 0)

该宏也用于初始化一个信号量,但它把信号量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);/* 释放信号量

BZ___172_141_1001_218_1078.png Linux自旋锁和信号量所采用的“获取锁—访问临界区—释放锁”的方式,姑且称之为“互斥三部曲”,实际存在于几乎所有的多任务操作系统之中,在WIN32、VxWorks等中皆如此。

代码清单7.3给出了使用信号量实现设备只能被一个进程打开的例子,等同于代码清单7.1 和7.2。

代码清单7.3 使用信号量实现设备只能被一个进程打开

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 }