信号量和管程
回顾:
并发问题:多线程并发导致资源竞争;
同步概念:协调多线程对共享数据的访问任何时刻只能有一个线程执行临界区代码;
确保同步的方法:底层硬件支持;高层次的编程抽象;
而今天我们要说的信号量和管程都是高层次的编程抽象中的一种;
一、什么叫做信号量
信号量是操作系统提供的一种协调共享资源访问的方法:
- 软件同步是平等线程间的一种同步协商机制;
- 而信号量是由操作系统进行管理的,地位高于进程;
- 信号量表示系统资源的数量。
举个例子,假设在球场上踢球,在没有裁判的情况下,就按场上既定的规则,但是当规则模糊不清时,就需要裁判,信号量相就相当于是裁判,具有最高地位。
信号量是一种抽象的数据类型:
信号量和车站的类比:
如图,假设有两个车站,刚开始是空的,则灯为绿,到两个车道被占满时,车站等为红后面再有车辆则无法进入处于等待区,当
车站里面的一个车辆出去后,则另外一个在等待的被唤醒,则可以进入车站。
二、信号量的特性
信号量是被保护的整数变量
- 初始化完成后,只能通过P()和V()操作修改
- 由操作系统保证,PV操作是原子操作。
原子操作的定义:所谓原子操作是指不会被线程调度机制打断的操作;这种操作一旦开始,就一直运行到结束,中间不会有任何 context switch (切[1] 换到另一个线程)。如果这个操作所处的层(layer)的更高层不能发现其内部实现与结构,那么这个操作是一个原子(atomic)操作,原子操作可以是一个步骤,也可以是多个操作步骤,但是其顺序不可以被打乱,也不可以被切割而只执行其中的一部分。将整个操作视作一个整体是原子性的核心特征。
三、信号量的使用
信号量的分类:
用信号量实现条件同步,如上图,假设线程A的N模块必须在线程B的X执行完之后再执行,
初始情况下,信号量置为0,则此时M模块执行完一次P()后,信号量为-1,则此时N模块进入等待状态,只有在X执行完之后,执行condition->V()后,信号量从-1变为0,则此N才会被唤醒进入执行,由此可以实现条件同步。
四、生产者消费者问题
使用信号量的困难:
五、管程
为了解决信号量存在的问题,引入了管程,因为信号量的PV操作,是在信号的生产者和消费者两个进程中的,而在两个不同的过程中PV操作很容易因为不配对的问题,在这里我们视图把配对的PV操作集中到一起,这就是我们所说的管程。
管程的定义:
管程是一种用于多线程互斥访问共享资源的程序结构:
- 采用面向对象的方法,简化了线程建的同步控制机制;
- 任何一个时刻最多只有一个线程执行管程代码
- 正在管程中的线程可临时放弃管程的互斥访问,等待事件出现时恢复。
管程的使用:
- 在对象/模块中,收集相关共享数据
- 定义访问共享数据的方法
管程和信号量的不同之处在于,管程可以先申请互斥操作,再检查信号量的状态,而信号量不可以,因为信号量方法不可以,因为在信号量方法的处理过程中,申请互斥操作需要进入临界区,而这时线程一旦占用了对临界区的互斥访问权限后,别人就再也进不来了,管程中的进入后如果不成功,则可以放弃对临界区的互斥访问权限。
第一种做法主要应用于os和java中。