信号量
信号量的使用
信号量(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,唤醒等待者。 信号量一般这样被使用,如下所示: