信号量
1. 概念
信号量(Semaphore)是操作系统中最典型的用于 同步 和 互斥 的手段。信号量的值可以是0、1或者n。
信号量与操作系统中的经典概念PV操作对应:
P(S):
① 将信号量S的值减1,及S = S - 1
;
② 如果 S ≥ 0,则该进程继续执行;否则该进程置为等待队列。
V(S):
①将信号量S的值加1,即S = S + 1
;
②如果 S>0,唤醒队列中等待信号量的进程。
2. 信号量的常见操作
(1)定义信号量:
// 定义名称为sem的信号量:
struct semaphore sem;
(2)初始化信号量:
// 该函数初始化信号量,并设置信号量sem的值为val
void sema_init(struct semaphore *sem, int val);
(3)获得信号量(请求信号量):
方法①:down() - 不推荐
/*
* 【作用】:该函数用于获得信号量sem(不可中断,不推荐使用)
*
* 【机制】:
* - 首先进行信号量资源数的查看
* - 如果信号量数据(count)不为0,则把其减1,并返回,调用成功;
* - 否则,调用__down进行等待,调用者进行睡眠。
*
* 【注意】:
* - 此函数的调用将会到致调用线程的睡眠,直到获取到信号,且该函数的调用不允许中断
* - 调用此函数后进入睡眠状态的进程不能被信号打断,所以不能在中断上下文中使用!
*/
void down(struct semaphore *sem);
down()函数实现:
方法②:down_interruptible()
/* 【作用】该函数用于获得信号量sem(可中断)
*
* 能被信号打断,因此该函数有返回值来区分是正常返回还是被信号中断。
* - 如果返回0,表示获得信号量正常返回;
* - 如果返回-EINTR,表示被信号打断。
*/
int down_interruptible(struct semaphore *sem);
down_interruptible()函数实现:
方法③:down_trylock()
/*
* 【作用】该函数尝试获得信号量,并根据情况返回相应的值。
* - 如果能立即获得,就获得该信号量并返回0;
* - 否则,返回非0值
*
* 【注意】
* - 不管有无可用信号量,都马上返回(如果返回0,则获取信号量成功,如果返回1,则获取失败)
* - 不会导致调用者睡眠,所以可以在中断上下文中使用。
*/
int down_trylock(struct semaphore *sem);
down_trylock()函数实现:
(4)释放信号量:
/*
* 【作用】释放信号量sem,唤醒等待者
*
* 【机制】调用了wake_up_process来唤醒进程
*/
void up(struct semaphore *sem);
3. 信号量的作用
用于 同步 和 互斥的手段。
(注意:新内核推荐直接使用 mutex作为互斥手段,信号量不再被推荐用于互斥)
信号量可以保护临界区,使用方式和自旋锁类似。只有得到信号量的进程才能执行临界区的代码。
- 自旋锁:获取不到信号量时,进程会原地打转。
- 信号量:获取不到信号量时,进程进入休眠等等状态。