使用场景信号量为控制并发程序的执行提供了强有力工具 , 这里列举两个场景:
互斥信号量提供了了一种很方便的方法来保证对共享变量的互斥访问 , 基本思想是
将每个共享变量(或一组相关的共享变量)与一个信号量 s (初始化为1)联系起来 , 然后用 wait/signal 操作将相应的临界区包围起来 。二元信号量也被称为互斥锁(mutex , mutual exclusve, 也称为 binary semaphore) , wait 操作相当于加锁 , signal 相当于解锁 。一个被用作一组可用资源的计数器的信号量称为计数信号量(counting semaphore)
调度共享资源除了互斥外 , 信号量的另一个重要作用是调度对共享资源的访问 , 比较经典的案例是生产者消费者 , 伪代码如下:
emptySem = NfullSem = 0// Producerwhile(whatever) {locally generate itemwait(emptySem)fill empty buffer with itemsignal(fullSem)}// Consumerwhile(whatever) {wait(fullSem)get item from full buffersignal(emptySem)use item}POSIX 实现POSIX 标准中有定义信号量相关的逻辑 , 在 semaphore.h 中 , 为 sem_t 类型 , 相关 API:// Intialize: sem_init(&theSem, 0, initialVal);// Wait: sem_wait(&theSem);// Signal: sem_post(&theSem);// Get the current value of the semaphore:sem_getvalue(&theSem, &result);信号量主要有两个缺点:- Lack of structure , 在设计大型系统时 , 很难保证 wait/signal 能以正确的顺序成对出现 , 顺序与成对缺一不可 , 否则就会出现死锁!
- Global visiblity , 一旦程序出现死锁 , 整个程序都需要去检查
MonitorsC. A. R. Hoare(也是 Quicksort 的作者) 在 1974 年的论文 Monitors: an operating system structuring concept 首次提出了「监控器」概念 , 它提供了对信号量互斥和调度能力的更高级别的抽象 , 使用起来更加方便 , 一般形式如下:
monitor1 . . . monitorMprocess1 . . . processN我们可以认为监控器是这么一个对象:- 所有访问同一监控器的线程通过条件变量(condition variables)间接通信
- 某一个时刻 , 只能有一个线程访问监控器
- wait(cv, m) 等待 cv 成立 , m 表示与监控器关联的一 mutex 锁
- signal(cv) 也称为 notify(cv) 用来通知 cv 成立 , 这时会唤醒等待的线程中的一个执行 。根据唤醒策略 , 监控器分为两类:Hoare vs. Mesa , 后面会介绍
- broadcast(cv) 也称为 notifyAll(cv) 唤醒所有等待 cv 成立的线程
// initializepthread_cond_init() pthread_cond_wait(&theCV, &someLock);pthread_cond_signal(&theCV);pthread_cond_broadcast(&theCV);使用方式在 pthreads 中 , 所有使用条件变量的地方都必须用一个 mutex 锁起来 , 这是为什么呢?看下面一个例子:pthread_mutex_t myLock;pthread_cond_t myCV;int count = 0;// Thread Apthread_mutex_lock(&myLock);while(count < 0) {pthread_cond_wait(&myCV, &myLock);}pthread_mutex_unlock(&myLock);// Thread Bpthread_mutex_lock(&myLock);count ++;while(count == 10) {pthread_cond_signal(&myCV);}pthread_mutex_unlock(&myLock);如果没有锁 , 那么- 线程 A 可能会在其他线程将 count 赋值为10后继续等待
- 线程 B 无法保证加一操作与测试 count 是否为零 的原子性
推荐阅读
- Java5,6,7,8的主要新特性归纳
- Java环境搭建,环境变量配置
- IPv6基础了解和配置
- JavaScript 字符串中的 pad 方法
- Java中的21种锁,图文并茂的详细解释
- Javascript中类型知识和valueOf和toString()方法
- javascript事件流
- 盘点2020JavaScript游戏框架
- Java分布式锁看这篇就够了
- 网络高并发
