面试题:PV操作底层与原理

Posted 森明帮大于黑虎帮

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了面试题:PV操作底层与原理相关的知识,希望对你有一定的参考价值。

一、基础概念

1、进程:进程是一个具有一定独立功能的程序关于某个数据集合的一次运行活动。它是操作系统动态执行的基本单元,在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元。

2、进程PCB:系统为了管理进程设置的一个专门的数据结构,用它来记录进程的外部特征,描述进程的运动变化过程。系统利用PCB来控制和管理进程,所以PCB是系统感知进程存在的唯一标志。进程与PCB是一一对应的)。

3、临界区:每个进程中访问临界资源的那段程序称为临界区(临界资源是一次仅允许一个进程使用的共享资源)。每次只准许一个进程进入临界区,进入后不允许其他进程进入。

4、锁:在多线程编程中,操作系统引入了锁机制。通过锁机制,能够保证在多核多线程环境中,在某一个时间点上,只能有一个线程进入临界区代码,从而保证临界区中操作数据的一致性。

5、死锁:一个进程需要独占访问不止一种资源。而操作系统允许多个进程并发致性共享系统资源时,此时可能会出现进程永远被阻塞的现象。这种现象称为死锁。

二、信号量和P、V操作

1、信号量:1965年荷兰的计算机科学家E.W.Dijkstra提出的新的同步工具。他将交通管制中多种颜色的信号灯管理交通的方法引入操作系统,让两个或多个进程通过信号量展开交互。信号量常常用一个记录型数据结构表示,它有两个分项:信号量的值,信号量队列的队列指针。例:信号量是一个二元数组(s,q)。可以这么理解s信号量的状态(一个整数),s的初值不为负数(和交通灯类似)。q是它的等待队列,建立信号量时q为空。

  • s >=0 : 绿灯
  • s < 0 :红灯

2、原语:信号量仅能由同步原语对其进行操作,而原语是执行时不可中断的过程,即原子操作。Dijkstra发明了两个同步原语:P操作和V操作,此外还用的符号有:wait和signal,up和down,sleep和wakeup。利用信号量和P、V操作既可以解决并发进程的的竞争问题,又可以解决进程的协作问题。例:对信号量状态进行改变,P调用一次-1,V调用一次+1。

3、上锁原语:

lock:(w锁位为1,表示已上锁)
{
    while(w == 1)
    {
        保护现场进程CPU现场;
        将现行进程的pcb插入w的等待队列;
        置该进程为“等待”状态;
        转进程调度;
    }
    w = 1;       //上锁
}

4、开锁原语:

lock:(w锁位为1,表示已上锁)
{
    while(w等待队列不为空)
    {
        移除等待队列首元素;
        将现行进程的pcb插入w的就绪队列;
        置该进程为“就绪”状态;
    }
    w = 0;       //开锁
}

5、P操作:
p(s)是一个原语操作,p操作执行 s– ,若s为负数,调用p(s)的进程被阻塞,放到等待队列q中。

p(s)
{
    s- -;
    if (s < 0)
    {
        保留调用进程的CPU现场;
        将进程的pcb插入到s的等待队列;
        把进程变为“等待状态”;
        转到进程调度;
    }
}

6、V操作 :
v(s)刚好与p(s)操作相反,v操作执行 s++ ,若s为大于0,继续执行;s <=0,从信号灯等待队列移出一个进程,解除等待状态,返回本程序继续执行。

v(s)
{
    s++;
    if (s <= 0)
    {
        移出s等待队列首元素;
        将该进程的pcb插入就绪队列;
        设置该进程为“就绪状态”;
    }
}

三、pv原语

PV原语通过操作信号量来处理进程间的同步与互斥的问题。其核心就是一段不可分割不可中断的程序。 其基本思路是用一种新的变量类型(semaphore)来记录当前可用资源的数量。

semaphore有两种实现方式:

  • semaphore的取值必须大于或等于0。0表示当前已没有空闲资源,而正数表示当前空闲资源的数量。
  • semaphore的取值可正可负,负数的绝对值表示正在等待进入临界区的进程个数。

信号量是由操作系统来维护的,用户进程只能通过初始化和两个标准原语(P、V原语)来访问。初始化可指定一个非负整数,即空闲资源总数。

P原语:阻塞原语,负责把当前进程由运行状态转换为阻塞状态,直到另外一个进程唤醒它。操作为:申请一个空闲资源(把信号量减1),若成功,则退出;若失败,则该进程被阻塞;

V原语:唤醒原语,负责把一个被阻塞的进程唤醒,它有一个参数表,存放着等待被唤醒的进程信息。操作为:释放一个被占用的资源(把信号量加1),如果发现有被阻塞的进程,则选择一个唤醒之。

P原语操作的动作是:

  • sem减1。
  • 若sem减1后仍大于或等于零,则进程继续执行。
  • 若sem减1后小于零,则该进程被阻塞后进入与该信号相对应的队列中,然后转进程调度。

V原语操作的动作是:

  • sem加1;
  • 若相加结果大于零,则进程继续执行;
  • 若相加结果小于或等于零,则从该信号的等待队列中唤醒一等待进程,然后再返回原进程继续执行或转进程调度。

PV操作对于每一个进程来说,都只能进行一次,而且必须成对使用。在PV原语执行期间不允许有中断的发生。

P操作,原子减少S,然后如果S < 0,则阻塞当前线程。
V操作,原子增加S,然后如果S <= 0,则唤醒一个阻塞的线程。

信号量机制:
(1) 整型信号量:不满足“让权等待”。
(2) 记录型信号量:只可申请一类资源,该资源有n个,一次只可申请一个。将资源分光,多类资源时易产生死锁。
(3) AND型信号量:可申请n类资源,每类资源有m个,每次可申请每类资源中的一个。会将资源分光。
(4) 信号量集:可申请n类资源,每类资源有m个,每次可申请每类资源中的多个。但低于下限时,不予分配。

四、关于死锁的概念

1、死锁的原因:
1)因为系统资源不足。

2)进程运行推进的顺序不合适,保证有先后顺序。

3)资源分配不当等。

2、产生死锁的四个必要条件:
1)互斥条件:一个资源每次只能被一个进程使用。

2) 请求与保持条件:一个进程因请求资源而阻塞时,对已获得的资源保持不放。

3)不剥夺条件: 进程已获得的资源,在末使用完之前,不能强行剥夺。

4)循环等待条件:若干进程之间形成一种头尾相接的循环等待资源关系。存在一个进程等待序列{P1,P2,…,Pn},其中P1等待P2所占有的某一资源,P2等待P3所占有的某一 源,……,而Pn等待P1所占有的的某一资源,形成一个进程循环等待环。

3、解决死锁的方式. (后续会具体展开)
1)鸵鸟算法:对死锁视而不见。
2)死锁的防止:

(1)破坏死锁的四个必要条件中的任意一个即可防止死锁。(条件一:许多资源不能同时访问,条件三:适用于对主存资源和处理器资源的分配,而不适用于所有资源)

(2)静态分配策略(破坏条件二):一个进程在执行前就申请它所要的全部资源,直到它所要的资源都得到满足后才开始执行。这种策略严重降低了资源利用率。

(3)层次分配策略(破坏条件四):资源被分成多个层次,一个进程得到某一层的一个资源后,它只能再申请在较高一层的资源;当一个进程要释放某层的一个资源时,必须先释放所占用的叫高层的资源,当另一个进程获得了某一层的一次资源后,它想在申请该层中的另一个资源,那么,必须先释放该层中的已占资源。比静态分配在实现上要多花一点代价,但提高了资源使用率。然而,如果一个进咸亨使用资源的次序和系统内的规定各层资源的次序不同时,这种提高可能不明显。

以上是关于面试题:PV操作底层与原理的主要内容,如果未能解决你的问题,请参考以下文章

高薪程序员&面试题精讲系列43之HashMap扩容机制的底层实现原理,HashMap扩容后是如何进行rehash操作的?

Java面试题汇总

JVM17_Tomcat打破双亲委派机制执行顺序底层代码原理Tomcat|JDBC破坏双亲委派机制带来的面试题

Java面试题HashMap的底层实现原理

前端面试题之手写promise

Java面试题HashMap的底层原理和线程安全的替代方案