信号量与管程

一、信号量

1. 信号量是操作系统提供的一种协调共享资源访问的方法,用信号量表示系统资源的数量。

信号量是一种抽象数据类型,由一个整形(sem)变量和两个原子操作组成。

2. 这两个原子操作分别是

  • P()(Prllaag:荷兰语,尝试减少)
  1. sem减一
  2. 若sem<0,进入等待,否则继续
  • V()(Verhoog:荷兰语,增加)
  1. sem加一
  2. 若sem≤0,唤醒一个等待进程

3. 信号量的特性

  • 信号量是被保护的整数变量
  1. 初始化完成后,只能通过P() 和V()操作修改
  2. 由操作系统保证,PV操作是原子操作
  • P() 可能阻塞,V()不会阻塞
  • 通常假定信号量是“公平的”
  1. 线程不会无限期的阻塞在P() 操作
  2. 假定信号量等待按FSFO(先进先出)排队

4. 信号量的实现

二、信号量的使用

1. 信号量分类,可分为两种信号量

  • 二进制信号量:资源数目为0或1
  • 资源信号量:资源数目为任何非负值

两者等价,基于一个可以实现另一个。

2.用信号量实现临界区的互斥访问

每个临界区设置一个信号量,其初值为1。

 必须成对使用P()操作和V()操作

  • P()操作保证互斥访问临界资源
  • V()操作在使用后释放临界资源
  • PV操作不能次序错误,重复或遗漏

 3.用信号量实现条件同步

 同步:合作的并发进程需要按先后次序执行。例如:一个进程的执行依赖于合作进程的消息或信号。当一个进程没有得到来自合作进程的消息或信号时需阻塞等待,直到消息或信号到达才唤醒。

4. 消费者-生产者问题

 有界缓冲区的生产者-消费者问题描述

  • 一个或多个生产者在生成数据后放在一个缓冲区里
  • 单个消费者从缓冲区取出数据处理
  • 任何时刻只能有一个生产者或者消费者可访问缓冲区

5. 用信号量解决生产者-消费者问题

问题分析:

  • 任何时候时刻只能有一个线程操作缓冲区(互斥访问)
  • 缓冲区空时,消费者必须等待生产者(条件同步)
  • 缓冲区满时,生产者必须等待消费者(条件同步)

用信号量描述每个约束:

  • 二进制信号量mutex
  • 资源信号量fullBuffers
  • 资源信号量emptyBuffers

实现过程:

  1. 信号量赋值:mutex赋值为1,fullBuffers赋值为0,emptyBuffers赋值为n。
  2. Deposit线程:对emptyBuffers进行P操作,emptyBuffers减一,当emptyBuffers为0时,表示缓冲区满,作P操作将发生阻塞,需等待Remove线程中对emptyBuffers进行V操作,表示消费者从缓冲区移出了一次数据。从而完成了条件同步
  3. 对mutex进行P操作,mutex变为0,若此时切换到Remove线程,mutex再次执行P操作会发生堵塞,从而完成互斥的功能。
  4. 将数据c添加到缓冲区,并对mutex进行V操作,mutex加一,相当于解除锁定。
  5. fullBuffers进行V操作,fullBuffers加一,可表示生产者已经添加了一次数据到缓冲区。
  6. Remove线程:对fullBuffers进行P操作,若fullBuffers非零,则其值减一后继续往下执行。若fullBuffers的值为0,表示缓冲区没有数据,则对其进行P操作将引起阻塞,需等待Deposit线程中的V操作。从而完成了条件同步。
  7. 同Desposit线程,在将数据移出缓冲区的操作之前和之后分别对mutex进行P操作和V操作,可完成互斥功能。
  8. 对emptyBuffers进行V操作,emptyBuffers加一,表示消费者已经从缓冲区移出了一次数据。

问1:Deposit线程中emptyBuffers的P操作与mutex的P操作能否互换位置?

答:不能,因为P操作可能引起阻塞,如:当emptyBuffers为0时表示缓冲区满,此时先执行mutex的P操作,可继续往下执行,再对emptyBuffers执行P操作时,会被阻塞,到消费者线程,fullBufffers进行P操作,可继续往下执行,再对mutex执行P操作,此时mutex为0,会产生阻塞,从而不能继续往下执行到emptyBuffers的V操作,从而产生了死锁。

问2:Deposit线程中mutex的V操作与fullBuffers的P操作能否互换位置?

答:能,因为V操作的作用是使得信号量加一,并且唤醒等待的线程,因此不会产生阻塞,可以互换位置。

原文地址:https://www.cnblogs.com/cjsword/p/12209302.html