信号量的P操作和V操作

本文介绍了计算机科学家狄克斯特拉在艾恩德霍芬技术大学期间开发的THE Multiprogramming System操作系统,重点讲述了其中提出的进程状态管理和信号量机制,这些概念对现代操作系统的发展产生了深远的影响。

1962年,狄克斯特拉离开数学中心进入位于荷兰南部的艾恩德霍芬技术大学(Eindhoven Technical University)任数学教授。在这里,他参加了X8计算机的开发,设计与实现了具有多道程序运行能力的操作系统——THE Multiprogramming System。THE是艾恩德霍芬技术大学的荷兰文Tchnische Hoogeschool Eindhov –en的词头缩写。狄克斯特拉在THE这个系统中所提出的一系统方法和技术奠定了计算机现代操作系统的基础,尤其是关于多层体系结构,顺序进程之间的同步和互斥机制这样一些重要的思想和概念都是狄克斯特拉在THE中首先提出并为以后的操作系统如UNIX等所采用的。为了在单处理机的情况下确定进程(process)能否占有处理机,狄克斯特拉将每个进程分为“就绪”(ready)、“运行”(running)和“阻塞”(blocking)三个工作状态。由于在任一时刻最多只有一个进程可以使用处理机,正占用着处理机的进程称为“运行”进程。当某进程已具备了使用处理机的条件,而当前又没有处理机供其使用,则使该进程处于“就绪”状态。当运行进程由于某种原因无法继续运行下去时,就停止其占用处理机,使之进入“阻塞”状态,待造成其退出运行的条件解除,再进入“就绪”状态。而对系统中所有同时运行的进程,在一个进程访问共享数据时,另一个进程不访问该数据)和互斥(mutually- exclusive,指两个进程不能同时在一个临界区中使用同一个可重复使用的资源,诸如读写缓冲区)两个关系,狄克斯特拉巧妙地利用火车运行控制系统中的“信号灯”(semaphore,或叫”信号量”)概念加以解决。所谓信号灯,实际上就是用来控制进程状态的一个代表某一资源的存储单元。例如,P1和P2是分别将数据送入缓冲B和从缓冲B读出数据的两个进程,为了防止这两个进程并发时产生错误,狄克斯特拉设计了一种同步机制叫“PV操作”,P操作和V操作是执行时不被打断的两个操作系统原语。执行P操作P(S)时信号量S的值减1,若结果不为负则P(S)执行完毕,否则执行P操作的进程暂停以等待释放。执行V操作V(S)时,S的值加1,若结果不大于0则释放一个因执行P(S)而等待的进程。对P1和P2可定义两个信号量S1和S2,初值分别为1和0。进程P1在向缓冲B送入数据前执行P操作P(S1),在送入数据后执行V操作V(S2)。进程P2在从缓冲B读取数据前先执行P操作P(S2),在读出数据后执行V操作V(S1)。当P1往缓冲B送入一数据后信号量S1之值变为0,在该数据读出后S1之值才又变为1,因此在前一数未读出前后一数不会送入,从而保证了P1和P2之间的同步。我国读者常常不明白这一同步机制为什么叫PV操作,原来这是狄克斯特拉用荷兰文定义的,因为在荷兰文中,通过叫passeren,释放叫vrijgeven,PV操作因此得名。这是在计算机术语中不是用英语表达的极少数的例子之一。

信号量

     信号量是最早出现的用来解决进程同步与互斥问题的机制,

     包括一个称为信号量的变量及对它进行的两个原语操作。

     一. 信号量的概念

     1.信号量的类型定义

     每个信号量至少须记录两个信息:信号量的值和等待该信号量的进程队列。它的类型定义如下:(用类PASCAL语言表述)

         semaphore = record

              value: integer;

              queue: ^PCB;

            end;

       其中PCB是进程控制块,是操作系统为每个进程建立的数据结构。

     s.value>=0时,s.queue为空;

     s.value<0时,s.value的绝对值为s.queue中等待进程的个数;

     2.PV原语

     对一个信号量变量可以进行两种原语操作:p操作和v操作,定义如下:    procedure p(var s:samephore);

          {

            s.value=s.value-1;

            if (s.value<0) asleep(s.queue);

          }

       procedure v(var s:samephore);

          {

            s.value=s.value+1;

            if (s.value<=0) wakeup(s.queue);

     }

其中用到两个标准过程:

       asleep(s.queue);执行此操作的进程的PCB进入s.queue尾部,进程变成等待状态
wakeup(s.queue);将s.queue头进程唤醒插入就绪队列
     s.value初值为1时,可以用来实现进程的互斥。

     p操作和v操作是不可中断的程序段,称为原语。如果将信号量看作共享变量,则pv操作为其临界区,多个进程不能同时执行,一般用硬件方法保证。一个信号量只能置一次初值,以后只能对之进行p操作或v操作。

     由此也可以看到,信号量机制必须有公共内存,不能用于分布式操作系统,这是它最大的弱点。

     V原语的主要操作是:

     (1)sem加1;

     (2)若相加结果大于零,则进程继续执行;

     (3)若相加结果小于或等于零,则唤醒一阻塞在该信号量上的进程,然后再返回原进程继续执行或转进程调度。

     典型理解偏差:

     一,以V原语的1、2步来做,Sem不就永远大于0,那进程不就一直循环执行成为死循环了?

     二,Sem大于0那就表示有临界资源可供使用,为什么不唤醒进程?

     三,Sem小于0应该是说没有临界资源可供使用,为什么还要唤醒进程?

     析疑: 一,P操作对sem减1的。P、V原语必须成对使用!从而不会造成死循环。 二,Sem大于0的确表示有临界资源可供使用,而且这个时候没有进程被阻塞在这个资源上,也就是说没有进程因为得不到这类资源而阻塞,所以没有被阻塞的进程,自然不需要唤醒。 三,V原语操作的本质在于:一个进程使用完临界资源后,释放临界资源,使Sem加1,以通知其它的进程,这个时候如果Sem<0,表明有进程阻塞在该类资源上,因此要从阻塞队列里唤醒一个进程来“转手”该类资源。 比如,有2个某类资源,三个进程A、B、C、D要用该类资源,最开始Sem=2,当A进入,Sem=1,当B进入Sem=0,表明该类资源刚好用完, 当C进入时Sem=-1,表明有一个进程被阻塞了,D进入,Sem=-2。当A用完该类资源时,进行V操作,Sem=-1,释放该类资源,而这时Sem<0,表明有进程阻塞在该类资源上,于是唤醒一个。

     为了进一步加深理解,再引入二个问题: 四,如果是互斥信号量的话,应该设置信号量Sen=1,但是当有5个进程都访问的话,最后在该信号量的链表里会有4个在等待,也是说S=-4,那么第一个进程执行了V操作使S加1,释放了资源,下一个应该能够执行,但唤醒的这个进程在执行P操作时因S〈0 ,也还是执行不了,这是怎么回事呢? 五,Sem的绝对值表示等待的进程数,同时又表示临界资源,这到底是怎么回事? 析疑: 四,当一个进程阻塞了的时候,它已经执行过了P操作,并卡在临界区那个地方。当唤醒它时就立即进入它自己的临界区,并不需要执行P操作了,当执行完了临界区的程序后,就执行V操作。 五,当信号量Sem小于0时,其绝对值表示系统中因请求该类资源而被阻塞的进程数目.S大于0时表示可用的临界资源数。注意在不同情况下所表达的含义不一样。当等于0时,表示刚好用完。

<think>嗯,用户问的是信号量操作中的P操作V操作,需要我用中文解释一下。首先,我得回忆一下操作系统课程里学的关于进程同步的内容。信号量是荷兰的Dijkstra提出的,对吧?PV操作是用来控制并发进程中临界区的访问的,避免竞态条件。 信号量其实是一个整型变量,不过具体的实现可能会有更多的结构,比如等待队列什么的。P操作V操作是原子操作,也就是说在执行过程中不会被中断,这一点很重要,否则可能引发问题。 P操作对应的荷兰语是Proberen,意思是尝试,而V操作是Verhogen,意思是增加。不过在英文里,P通常被称为wait,V被称为signal。用户可能需要知道这些操作的用途基本机制。 接下来需要解释这两个操作的具体行为。P操作会先减少信号量的值,如果减之后值小于0,说明资源不足,进程需要被阻塞,进入等待队列。而V操作则是增加信号量,如果加之后的值还是小于等于0,说明有进程在等待,这时候要唤醒一个进程。 不过要注意,信号量的值初始化的方式不同,比如二进制信号量用01,而计数信号量可以有更多的资源数量。用户可能想知道它们的应用场景,比如互斥锁或者生产者消费者问题。 可能用户是在学习操作系统或者准备面试,需要理解这些基础概念。他们可能对具体的代码实现或者实际例子感兴趣。比如,用信号量实现互斥的时候,初始化信号量为1,然后PV包围临界区。 另,得注意区分信号量互斥锁的区别,虽然二进制信号量类似互斥锁,但信号量通常没有所有者,可以由不同线程释放,而互斥锁需要由获取的线程释放。这点可能在高级问题中才会涉及,但用户可能现在只需要基础。 总结一下,我应该先介绍信号量的概念,然后分别讲PV操作,再举例说明应用场景。可能需要用简单的例子,比如生产者消费者中的缓冲区访问。确保用中文通俗易懂,避免太专业的术语,但也要准确。</think>**信号量Semaphore)** 是操作系统中用于控制多进程/线程**同步与互斥**的一种机制,由荷兰计算机科学家 Edsger Dijkstra 提出。它本质上是一个整型变量,结合两个原子操作(**P操作****V操作**),实现对共享资源的访问控制。 --- ### **1. P操作(Proberen,荷兰语“尝试”)** - **作用**:申请资源(或获取锁)。 - **行为**: 1. 将信号量的值减1。 2. 若结果 ≥ 0,说明资源可用,进程继续执行。 3. 若结果 < 0,说明资源不足,进程被阻塞并加入等待队列。 - **别名**:`wait()` 或 `down()`。 - **伪代码**: ```c void P(Semaphore S) { S.value--; if (S.value < 0) { 将当前进程加入等待队列; 阻塞当前进程; } } ``` --- ### **2. V操作(Verhogen,荷兰语“增加”)** - **作用**:释放资源(或释放锁)。 - **行为**: 1. 将信号量的值加1。 2. 若结果 ≤ 0,说明有进程在等待,唤醒一个阻塞的进程。 - **别名**:`signal()` 或 `up()`。 - **伪代码**: ```c void V(Semaphore S) { S.value++; if (S.value <= 0) { 从等待队列中取出一个进程; 唤醒该进程; } } ``` --- ### **3. 信号量的类型** - **二进制信号量**:值只能为0或1,用于实现互斥(类似互斥锁)。 - **计数信号量**:值为非负整数,表示剩余资源数量(例如缓冲区空位数量)。 --- ### **4. 应用场景** 1. **互斥访问临界区** ```c Semaphore mutex = 1; // 初始化 // 进程A P(mutex); // 进入临界区前申请锁 // 临界区代码... V(mutex); // 退出临界区后释放锁 ``` 2. **生产者-消费者问题** - 用两个信号量分别表示缓冲区空位满位: ```c Semaphore empty = N; // 初始空位数量 Semaphore full = 0; // 初始满位数量 // 生产者 P(empty); // 申请空位 // 生产数据并放入缓冲区... V(full); // 增加满位 // 消费者 P(full); // 申请满位 // 取出数据并消费... V(empty); // 增加空位 ``` --- ### **5. 关键特性** - **原子性**:P/V 操作是原子操作执行过程不可中断。 - **阻塞机制**:资源不足时,进程主动阻塞而非忙等待(Busy Waiting)。 - **灵活性**:可协调多个进程/线程的并发行为。 --- ### **总结** - **P操作**是“申请资源”,可能导致进程阻塞。 - **V操作**是“释放资源”,可能唤醒其他进程。 - 信号量是解决并发问题(如死锁、竞态条件)的核心工具之一。
评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值