操作系统信号量与P、V操作 初步认识整理

本文介绍了操作系统中的信号量,包括整型、结构型和二值信号量,详细阐述了P、V操作的原理和使用,并通过实例分析了如何利用信号量解决进程的互斥和同步问题,如生产者-消费者问题、读者-写者问题等。最后,给出了使用信号量的几点提示,帮助理解信号量机制。
摘要由CSDN通过智能技术生成

初步接触,若有不足之处,请各位不吝赐教。谢谢!

首先介绍:信号量
信号量包括整型信号量、结构型信号量、二值信号量。

整型信号量

最初,将信号量定义为一个共享的整型量,它保存可供使用的唤醒数目。如果信号量的值为0,表示没有保存唤醒;如果它的值大于0,表示有一个或多个保留的唤醒。
对信号量的操作有以下限制:
1、信号量可以初始化为一个非负值
2、只能由PV两个操作来访问信号量。
P操作最初源于荷兰语proberen,表示测试;V操作源于荷兰语verhogen,表示增加。请读者注意,在有些书上将P操作称作wait或者DOWN操作,将V操作称作signal或者UP操作。
P和V操作定义的伪代码形式如下:

P(S)
//测试信号量S的值是否大于0,若是,则S的值减1,程序向下执行,如果不大于0,则循环测试。
{
   
 while (S <= 0);//不执行任何操作
 S--;
}

V(S)//只是简单地把S的值加1
{
   
 S++;
}

P和V操作都是原语,即单个的、不可分割的原子操作。
原语:是机器指令的延伸,往往是为完成某些特定的功能而编制的一段程序,它在执行时不可分割、不可中断。即一个操作中的所有动作要么全做,要么全不做。执行原语时要屏蔽中断,以保证其操作的不可分割性。)
一般使用方式是:当多个进程互斥进入临界区时,需要设置一个信号量mutex,其初值为1,这些进程进入、使用和退出临界区的构造形式是一样的。下面是其中任一进程Pi利用信号量实现互斥的伪代码形式:

do
{
   
 P(mutex);
 临界区
 V(mutex);
 其他代码区
} while (1);

主要缺点忙式等待问题:当一个进程处于临界区时,其它试图进入临界区的进程必须在入口处持续进行测试,很显然,这种循环测试、等待进入的方式在单CPU多到程序系统中存在很大问题,因为忙式等待要消耗CPU的时间,即使其它进程想用CPU做有效工作,也无法实现。这种类型的信号量也称“转锁”(Spinlock),因为当进程等待该锁打开时要“原地转圈”。然而,在多处理器系统中转锁仍得到应用。

结构型信号量

又称为记录型信号量、计数信号量,一般是由两个成员组成的数据结构。其中一个成员是整型变量,表示该信号量的值另一个是指向PCB(进程控制块,进程存在的唯一标识)的指针。当多个进程都等待同一个信号量时,它们就排成一个队列,由信号量的指针项指示该队列的队首,而PCB队列是通过PCB自身所包含的指针项进行链接的。最后一个PCB(即队尾)的链接指针为0。
可以将信号量定义为如下所示的一个C语言结构:

 typrdef struct
 {
   
  int value;
  struct  PCB  *list;
 }semaphore;
 信号量的值与相应资源的使用情况有关。当它的值大于0时,表示当前可用资源的数量
 当它的值小于0时其绝对值表示等待使用该资源的进程个数,即在该信号量队列上排队的PCB的个数。

在这里插入图片描述
对信号量的操作有如下严格的限制:
1、信号量可以赋初值,且初值为非负数。信号量的初值可由系统根据资源使用情况和使用需要来确定。在初始条件下,信号量的指针项可以置为0,表示队列为空。
2、在使用过程中信号量的值可以修改,但只能由P和V操作访问,不允许通过其他方式查看或操纵信号量。
设信号量为S,对S的P操作记为P(S),对S的V操作记为V(S)。
P、V操作的定义分别如下:

 void  P(semaphore  S)
 {
   
  S.value--;//信号量的值S.value减1
  if (S.value < 0)
//如果其值大于0,则该进程继续运行;如果其值小于0,则把该进程的状态置为阻塞,把相应的PCB链入该信号量队列的队尾,
//放弃处理机,进行等待(直至其它进程在S上执行V操作,把它释放出来为止)

  {
   
   把这个进程加到S.list队列;
   block();//block操作挂起调用它的进程
  }
 }


 void  S(semaphore)
 {
   
  S.value++;//信号量的值S.value加1
  if (S.value <= 0)
  // 如果其值大于0,则该进程继续运行;如果其值小于等于0,则释放信号量队列上的第一个PCB(即信号量指针项所指向的PCB)
    //  所对应的进程Q(把阻塞状态改为就绪状态),执行V操作的进程继续运行。
  {
   
   从S.list队列中移走进程Q;
   wakeup(Q);//wakeup(Q)操作恢复被阻塞进程Q的执行
  }
 }
 block()操作和wakeup(Q)操作被操作系统作为基本系统调用。

在具体实现时应注意P,V操作都是原语
上述阻塞状态进程链入相应队列末尾,以及将队列的队首进程从阻塞队列中移至就绪队列中采用的方法是FIFO(即先进先出)策略。然而,具体实现并不限于此,管理队列可以采用任何一种链接策略。信号量使用是否正确与信号量队列的排队策略无关

二值信号量

它是上述信号量的一种特例,它的值只能在0和1之间选择。依赖于底层的硬件体系结构,二值信号量比计数信号量更容易实现二值信号量类似互斥锁。
二值信号量及其操作的定义用C语言描述如下:

 typedef  struct
 {
   
  enum{
   false,true}value;//枚举量
  struct  PCB   *list;
 }B_semaphore;
 void  P_B(B_semaphore  S)
 {
   
  if (S.value == true)
   S.value = false;
  else
  
  • 16
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值