信号量
-
锁的不足
- 多线程同时执行访问临界区
- 互斥和条件同步
-
含义
- 包含一个信号量sem(semaphore,有符号整数) 和两个原子操作:P操作和V操作
- sem变量受保护。初始化后,改变信号量的唯一方法是P()和V()。两个操作必须是原子的
- P()能够阻塞,V()不会阻塞
- 假定信号量是公平的:实践中,通常使用FIFO,利用队列决定唤醒哪个进程 ⇒ 上一章的Spinlock是FIFO类型吗?
- 包含一个信号量sem(semaphore,有符号整数) 和两个原子操作:P操作和V操作
-
用途
- 互斥
- 条件同步(调度约束 —— 一个进程等待另一个进程的事件发生)
-
两种类型信号量
-
二进制信号量:0或1 ⇒ 模拟lock操作
-
模拟lock操作
mutex = new Semaphore(1); //sem初值置1 ... mutex->P(); ... Critical Section; ... mutex->V();
-
实现简单的调度/同步约束(线程A的P()后面的代码需等待线程B执行到V()后才继续执行)
-
-
一般/计数信号量:可取任何非负值
-
解决复杂的调度/同步问题
-
-
-
信号量的实现
class Semaphore{ int sem; waitQueue q; } Semaphore::P(){ //该原子操作的语义 sem--; if(sem < 0){ Add this thread t to q; block(t); } } Semaphore::V(){ //该原子操作的语义 sem++; if(sem <= 0){ Remove a thread t from q; wakeup(t); } }
-
不足
- 读/开发代码比较困难
- 程序员必须非常精通信号量
- 容易出错
- 使用的信号量被另一个线程占用
- 忘记释放信号量
- 不能解决死锁问题
- 读/开发代码比较困难
管程
- 抽象程度比信号量更高。处于语言层面
- 目的:分离互斥和条件同步的关注