操作系统——进程与线程

进程

现代操作系统允许多个程序并发执行,为了更好地描述和控制程序的并发执行,从而引入了进程的概念。程序和进程的区别如下:

  • 程序:是静态的,是一个存放在磁盘里的可执行文件,是一个指令的集合。
  • 进程:是动态的,是程序的一次执行过程

进程的组成

进程是一个独立的运行单位,也是操作系统进行资源分配的基本单位。它由以下三部分组成:

  • 进程控制块(PCB):PCB是一个专门的数据结构。操作系统利用PCB来描述进程的基本情况和运行状态,进而控制和管理进程。所谓创建进程,就是创建进程的PCB;而撤销进程,就是撤销进程的PCB。
  • 程序段:程序段就是能被进程调度程序调度到CPU执行的程序代码段,多个进程可以共享同一个程序段。
  • 数据段:一个进程的数据段,可以是进程对应的程序加工处理的原始数据,也可以是程序执行时产生的中间或最终结果。

进程状态

由于操作系统中各进程之间的相互制约及操作系统运行环境的变化,使得进程的状态也在不断地发生变化。通常进程有以下5种状态:

  • 创建态:创建进程需要多个步骤,首先申请一个空白PCB,并向PCB中填写用于控制和管理进程的信息;然后为该进程分配运行时所必须的资源;最后把该进程转入就绪态并插入就绪队列。但是,如果进程所需的资源尚不能得到满足(如内存不足),则创建工作尚未完成,进程此时所处的状态就是创建态。
  • 就绪态:进程获得了除CPU外的一切所需资源,一旦得到CPU,便可立即运行。系统中处于就绪态的进程可能有多个,通常将它们排成一个队列,称为就绪队列
  • 阻塞态:进程正在等待某一事件(如等待某资源为可用或等待IO完成)而暂停运行,即使CPU空闲,该进程也不能运行。系统通常将处于阻塞态的进程也排成一个队列,称为阻塞队列。甚至根据阻塞原因的不同,设置多个阻塞队列。
  • 运行态:进程正在计算机上运行。在单核计算机中,每个时刻只有一个进程处于运行态。
  • 结束态:进程正从系统中消失,可能是进程正常结束或其它原因退出运行。进程需要结束运行时,系统首先将该进程置为结束态,然后进一步处理资源释放和回收等工作。

前三种是进程的基本状态,它们之间的状态转换如下:

  • 就绪态 → \rightarrow 运行态:处于就绪态的进程被调度后,获得CPU,于是进程由就绪态转换为运行态。
  • 运行态 → \rightarrow 就绪态:处于运行态的进程在时间片用完后,不得不让出CPU,从而进程由运行态转换为就绪态。此外,在可剥夺的操作系统中,当有更高优先级的进程就绪时,调度程序将正在执行的进程转换为就绪态,让更高优先级的进程执行。
  • 运行态 → \rightarrow 阻塞态(主动):进程请求某资源的使用和分配或等待某一事件的发生时,它就从运行态转换为阻塞态。
  • 阻塞态 → \rightarrow 就绪态(被动):进程等待的事件到来时,中断处理程序必须把相应进程的状态由阻塞态转换为就绪态。

在这里插入图片描述

进程控制

进程控制的主要功能是对操作系统中的所有进程实施有效的管理,它具有创建新进程、撤销已有进程、实现进程状态转换等功能。进程控制是通过原语实现的。

原语

操作系统结构可以从不同方向划分,但从操作系统的发展来看,从操作系统的内核架构划分的方式得到了长足的发展:

在这里插入图片描述

其中原语是一些可以被调用的公用小程序,它们各自完成一个规定的动作,它们的特点如下:

  • 处于操作系统的最底层,最接近硬件的部分。
  • 原语的运行具有原子性。
  • 运行的时间比较短,而且调用频繁。

定义原语的直接方法就是关闭中断,让其所有动作不可分割的完成后再打开中断。

进程创建

操作系统允许一个进程创建另一个进程,此时创建者称为父进程,被创建的进程称为子进程。子进程可以继承父进程所拥有的资源。当子进程被撤销时,应将其从父进程那里获得的资源归还给父进程。此外,在撤销父进程时,通常也会同时撤销其所有的子进程。操作系统创建一个新进程的过程如下(创建原语):

  • 为新进程分配一个唯一的进程标识号PID,并申请一个空白PCB(PCB是有限的)。若PCB申请失败,则创建失败。
  • 为进程分配其运行所需的资源,这些资源或从操作系统获得,或仅从其父进程获得。如果资源不足,则并不是创建失败,而是处于创建态,等待资源。
  • 初始化PCB,主要包括初始化标志信息、初始化计算机状态信息和初始化计算机控制信息,以及设置进程的优先级等。
  • 若进程就绪队列能够接纳新进程,则将新进程插入就绪队列,等待被调度运行。

进程终止

操作系统终止进程的过程如下(终止原语):

  • 根据被终止进程的PID,检索出该进程的PCB,从中读出该进程的状态。
  • 若要被终止进程处于执行状态,立即终止该进程的执行,并将计算机资源分配给其它进程。
  • 若该进程还有子孙进程,则应将其所有子孙进程终止。
  • 将该进程所拥有的全部资源,归还给其父进程或操作系统。
  • 将该PCB从所在队列中删除。

进程阻塞和唤醒

正在执行的进程,由于期待的某些事件未发生,进程便通过调用阻塞原语,使自己由运行态变为阻塞态。阻塞原语的执行过程如下:

  • 找到将要被阻塞进程的PCB。
  • 若该进程为运行态,则保护其现场,将其状态转为阻塞态,停止运行。
  • 把该PCB插入相应事件的等待队列,将CPU调度给其它就绪进程。

当被阻塞进程所期待的事件出现时,由有关进程调用唤醒原语,将等待该事件的进程唤醒。唤醒原语的执行过程如下:

  • 在该事件的等待队列中找到相应进程的PCB。
  • 将其从等待队列中移出,并置其状态为就绪态。
  • 把该PCB插入就绪队列,等待调度程序调度。

注意,阻塞原语和唤醒原语是一对作用刚好相反的原语,必须成对使用。如果在某进程中调用了阻塞原语,则必须在与之合作的或其它相关的进程中安排一条相应的唤醒原语,以便唤醒阻塞进程。否则,阻塞进程将会因不能被唤醒而永久地处于阻塞状态。

进程通信

进程通信是指进程之间的信息交互,常用的通信方式有以下三种:

  • 共享存储:在通信的进程之间存在一块可直接访问的共享空间,通过对这片共享空间进行读写操作实现进程之间的信息交换。在对共享空间进行读写操作时,需要使用同步互斥工具进行控制。共享存储又分为两种:低级方式的共享是基于数据结构的共享;高级方式的共享则是基于存储区的共享。操作系统只负责为通信进程提供可共享使用的存储空间和同步互斥工具,而数据交换则由用户自己安排读写指令完成。
  • 消息传递:进程通过操作系统提供的发送消息和接收消息两个原语进行数据交换。这种方式隐藏了通信实现细节,使通信过程对用户透明,简化了通信程序的设计,是当前应用最广泛的进程间通信机制。消息传递的方式有以下两种:
    • 直接通信方式:发送进程直接把消息发送给接收进程,并将它挂在接收进程的消息缓冲队列上,接收进程从消息缓冲队列中取得消息。
    • 间接通信方式: 发送进程把消息发送到某个中间实体,接收进程从中间实体取得消息。这种中间实体一般称为信箱。该通信方式广泛应用于计算机网络中。
  • 管道通信:所谓管道,是指用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,又名pipe文件。写进程以字符流形式将大量的数据送入管道,读进程从管道中接收数据。管道的特点如下:
    • 管道只能进行半双工通信,即某个时间内数据只能单向流动。
    • 当管道写满时,写进程就会被阻塞,直到管道内的数据被读走。
    • 当管道读空时,读进程就会被阻塞,直到管道被写入数据。
    • 管道内的数据一旦被读走,就会彻底消失,因此一个管道允许多个写进程和一个读进程。

线程

线程组成

引入线程的目的是减小程序在并发执行时所付出的时空开销。线程是进程中的一个实体,是操作系统调度的基本单位,线程自己不拥有系统资源,只拥有一点在运行中必不可少的资源,但它可与同属一个进程的其它线程共享进程所拥有的全部资源。与进程类似,系统也为每个线程配置一个线程控制块TCB,用于记录控制和管理线程的信息。TCB通常包括:

  • 线程标识符。
  • 一组寄存器,包括程序计数器、状态寄存器和通用寄存器。
  • 线程运行状态,用于描述线程正处于何种状态。
  • 优先级。
  • 线程专有存储区,线程切换时用于保存现场等。
  • 堆栈指针,用于过程调用时保存局部变量及返回地址等。

引入线程后,进程的内涵发生了改变:进程只作为除CPU外的系统资源的分配单元,而线程则作为CPU的分配单元。引入线程操作系统的变化如下:

  • 调度:在传统的操作系统中,拥有资源和独立调度的基本单位都是进程,每次调度都要进行上下文切换,开销较大。在引入线程的操作系统中,线程是独立调度的基本单位。在同一进程中,线程的切换不会引起进程切换。但从一个进程中的线程切换到另一个进程中的线程时,会引起进程切换。
  • 并发性:在引入线程的操作系统中,不仅进程之间可以并发执行,而且一个进程中的多个线程之间亦可并发执行,甚至不同进程中的线程也能并发执行。
  • 拥有资源:进程是系统中拥有资源的基本单位,而线程不拥有系统资源,但线程可以访问其隶属进程的系统资源,这主要表现在属于同一进程的所有线程都具有相同的地址空间。
  • 独立性:每个进程都拥有独立的地址空间和资源,除了共享全局变量,不允许其它进程访问。某进程中的线程对其它进程不可见。同一进程中的不同线程是为了提高并发性及进行相互之间的合作而创建的,它们共享进程的地址空间和资源。
  • 系统开销:在创建或撤销进程时,系统都要为之分配或回收PCB及其它资源。操作系统为此所付出的开销,明显大于创建或撤销线程时的开销。类似地,在进程切换时涉及进程上下文的切换,而线程切换时只需保存和设置少量寄存器内容,开销很小。此外,由于同一进程内的多个线程共享进程的地址空间,因此,这些线程之间的同步与通信非常容易实现,甚至无须操作系统的干预。
  • 支持多核CPU:对于传统单线程进程,无论CPU核心有多少个,进程只能运行在一个核心上,对于多线程进程,可以将线程分配到多个核心上运行。

线程的实现方式

线程的实现可以分为两类:用户级线程(ULT)和内核级线程(KLT)。

用户线程

在用户级线程中,有关线程管理的所有工作都由应用程序在用户态中完成,内核意识不到线程的存在。应用程序可以通过使用线程库设计成多线程程序。

在这里插入图片描述

对于设置了用户级线程的系统,其调度仍是以进程为单位进行的,各个进程轮流执行一个时间片。假设进程A包含1个用户级线程,进程B包含100 个用户级线程,这样,进程A中线程的运行时间将是进程B中各线程运行时间的100倍。用户线程的优点如下:

  • 线程切换不需要转换到内核空间,节省了模式切换的开销。
  • 调度算法可以是进程专用的,不同的进程可根据自身的需要,对自己的线程选择不同的调度算法。
  • 用户级线程的实现与操作系统平台无关,对线程管理的代码是属于用户程序的一部分。

用户线程的缺点如下:

  • 系统调用的阻塞问题,当线程执行一个系统调用时,不仅该线程被阻塞,而且进程内的所有线程都被阻塞。
  • 不能发挥多核CPU的优势,内核每次分配给一个进程的仅有一个CPU,因此进程中仅有一个线程能执行。

内核线程

在操作系统中,无论是系统进程还是用户进程,都是在操作系统内核的支持下运行的,与内核紧密相关。内核级线程同样也是在内核的支持下运行的,线程管理的所有工作也是在内核空间内实现的。内核空间也为每个内核级线程设置一个TCB,内核根据TCB感知某线程的存在,并对其加以控制。

在这里插入图片描述

内核线程的优点如下:

  • 能发挥多核CPU的优势,内核能同时调度同一进程中的多个线程并行执行。
  • 如果进程中的一个线程被阻塞,内核可以调度该进程中的其它线程占用CPU,也可运行其它进程中的线程。
  • 内核支持线程具有很小的数据结构和堆栈,线程切换比较快、开销小。
  • 内核本身也可采用多线程技术,可以提高系统的执行速度和效率。

内核线程的缺点: 同一进程中的线程切换,需要从用户态转到核心态进行,系统开销较大。这是因为用户进程的线程在用户态运行,而线程调度和管理是在内核实现的。

混合方式

在组合实现方式中,内核支持多个内核级线程的建立、调度和管理,同时允许用户程序建立、调度和管理用户级线程。一些内核级线程对应多个用户级线程,这是用户级线程通过时分多路复用内核级线程实现的。同一进程中的多个线程可以同时在多处理机上并行执行,且在阻塞一个线程时不需要将整个进程阻塞,所以混合方式能结合KLT和ULT的优点,并且克服各自的不足。

在这里插入图片描述

线程状态

与进程一样,各线程之间也存在共享资源和相互合作的制约关系,致使线程在运行时也具有间断性。相应地,线程在运行时也具有以下三种基本状态:

  • 运行状态:线程已获得CPU而正在运行。
  • 就绪状态:线程已具备各种执行条件,只需再获得CPU便可立即执行。
  • 阻塞状态:线程在执行中因某事件受阻而处于暂停状态。

线程这三种基本状态之间的转换和进程基本状态之间的转换是一样的。

线程控制

  • 线程的创建:操作系统中有用于创建线程和终止线程的函数(或系统调用)。用户程序启动时,通常仅有一个称为初始化线程的线程正在执行,其主要功能是用于创建新线程。在创建新线程时,需要利用一个线程创建函数, 并提供相应的参数。线程创建函数执行完后,将返回一个线程标识符。
  • 线程的终止:当一个线程完成自己的任务后,或线程在运行中出现异常而要被强制终止时,由终止线程调用相应的函数执行终止操作。但是有些线程(主要是系统线程)一旦被建立,便一直运行而不会被终止。通常,线程被终止后并不立即释放它所占有的资源,只有当进程中的其它线程执行了分离函数后,被终止线程才与资源分离,此时的资源才能被其它线程利用。被终止但尚未释放资源的线程仍可被其它线程调用,以使被终止线程重新恢复运行。

CPU调度

CPU调度是对CPU进行分配,以实现进程并发地执行。CPU调度是多道程序操作系统的基础,是操作系统设计的核心问题。

调度的层次

作业是指一个具体的任务,提交作业是指用户让操作系统发起一些程序来处理一个任务,一个作业从提交开始直到完成,往往要经历以下三级调度:

  • 高级调度(作业调度):按照一定的原则从外存上处于后备队列的作业中挑选一个(或多个)调入内存并创建进程,每个作业只调入一次、调出一次。作业调入时会建立PCB,作业调出时才撤销PCB。
  • 中级调度(内存调度):中级调度的目的是提高内存利用率和系统吞吐量,为此,将那些暂时不能运行的进程调至外存等待,此时进程的状态称为挂起态。当它们已具备运行条件且内存又稍有空闲时,由中级调度来决定把外存上的那些己具备运行条件的就绪进程再重新调入内存,并修改其状态为就绪态,挂在就绪队列上等待。
  • 低级调度(进程调度):按照某种算法从就绪队列中选取一个进程,将CPU分配给它。

在这里插入图片描述

进程调度

进程调度是最基本的一种调度,在各种操作系统中都必须配置这级调度。

进程调度的时机

当前正在运行的进程主动或被动放弃CPU时,才会发生调度事件从而运行调度程序,调度了新的就绪进程后,才会进行进程切换。理论上这三件事情应该顺序执行,但在实际的操作系统内核程序运行中,若某时刻发生了引起进程调度的因素,则不一定能马上进行调度与切换:

  • 在处理中断的过程中:中断处理过程复杂,在实现上很难做到进程切换,而且中断处理是系统工作的一部分,逻辑上不属于某一进程,不应被剥夺CPU资源。
  • 进程在操作系统内核临界区中:进入临界区后,需要独占式地访问,理论上必须加锁,以防止其它并行进程进入,在解锁前不应切换到其它进程,以加快临界区的释放。
  • 需要完全屏蔽中断的原子操作过程:在原子过程中,连中断都要屏蔽,更不应该进行进程调度与切换。

进程切换往往在调度完成后立刻发生,进程切换需要保存当前进程状态并恢复另一个进程的状态,这个任务称为上下文切换。上下文是指某一时刻CPU寄存器和程序计数器的内容。进行上下文切换时,内核会将旧进程状态保存在其PCB中,然后加载经调度而要执行的新进程的上下文。

进程调度的策略

进程调度通常有以下两种实现方式:

  • 非抢占调度策略(主动放弃CPU):是指当一个进程正在执行时,即使有某个更为重要或紧迫的进程进入就绪队列,仍然让正在执行的进程继续执行,直到该进程执行完成或发生某种事件而进入阻塞态时,才把CPU分配给其它进程。非抢占调度方式的优点是实现简单、系统开销小,适用于大多数的批处理系统,但它不能用于分时系统和大多数的实时系统。
  • 抢占调度策略(被动放弃CPU):是指当一个进程正在执行时,若有某个更为重要或紧迫的进程需要使用CPU,则允许调度程序根据某种原则去暂停正在执行的进程,将CPU分配给这个更为重要或紧迫的进程。

调度程序

用于进程调度的程序称为调度程序,它通常由三部分组成:

  • 排队器:将系统中的所有就绪进程按照一定的策略排成一个或多个队列,以便于调度程序选择。每当有一个进程转变为就绪态时,排队器便将它插入到相应的就绪队列中。
  • 分派器:依据调度程序所选的进程,将其从就绪队列中取出,将CPU分配给新进程。
  • 上下文切换器:在对CPU进行切换时,会发生两对上下文的切换操作:
    • 第一对,将当前进程的上下文保存到其PCB中,再装入分派程序的上下文,以便分派程序运行;
    • 第二对,移出分派程序的上下文,恢复新选程序的上下文。

在非抢占式调度策略下,只有运行进程阻塞或退出才触发调度程序工作。在抢占式调度策略下,每个时钟中断都有可能触发调度程序工作。

闲逛进程

闲逛进程是调度程序的备胎,当发生进程调度且就绪队列没有其它进程时,调度程序就会调度闲逛进程运行,直到出现其它就绪进程为止。就绪进程的特点如下:

  • 优先级最低。
  • 能耗低。

两种线程的调度

如果操作系统支持线程,那么调度程序调度的对象将有所不同:

  • 不支持内核线程的操作系统,调度程序的调度对象依旧是进程。
  • 支持内核线程的操作系统,调度程序的调度对象就是内核线程。

调度算法

调度算法的评价指标

  • CPU利用率:CPU利用率是指CPU忙碌的时间占总时间的比例。
    C P U 利用率 = 忙碌的时间 总时间 CPU利用率=\frac{忙碌的时间}{总时间} CPU利用率=总时间忙碌的时间
  • 系统吞吐量:指单位时间内完成作业的数量
    系统吞吐量 = 总共完成了多少道作业 总共花了多少时间 系统吞吐量=\frac{总共完成了多少道作业}{总共花了多少时间} 系统吞吐量=总共花了多少时间总共完成了多少道作业
  • 周转时间:是指作业提交到作业完成所经历的时间。它包括高级调度时间、低级调度时间、进程在CPU的执行时间以及进程等待I/O的阻塞时间。
    周转时间 = 作业完成时间 − 作业提交时间 周转时间=作业完成时间-作业提交时间\\ 周转时间=作业完成时间作业提交时间
    平均周转时间指多个作业周转时间的平均值:
    平均周转时间 = 各作业周转时间之和 作业数 平均周转时间=\frac{各作业周转时间之和}{作业数}\\ 平均周转时间=作业数各作业周转时间之和
    带权周转时间指作业周转时间与作业实际运行时间的比值:
    带权周转时间 = 作业周转时间 作业实际运行时间 带权周转时间=\frac{作业周转时间}{作业实际运行时间}\\ 带权周转时间=作业实际运行时间作业周转时间
    平均带权周转时间是指多个作业带权周转时间的平均值:
    平均带权周转时间 = 各作业带权周转时间之和 作业数 平均带权周转时间=\frac{各作业带权周转时间之和}{作业数} 平均带权周转时间=作业数各作业带权周转时间之和
  • 等待时间:指作业等待CPU的时间之和。
  • 响应时间:指用户提出请求到首次产生响应的时间。

算法分类

在这里插入图片描述

同步与互斥

在多道程序环境下,进程是并发执行的,不同进程之间存在着不同的相互制约关系。为了协调进程之间的相互制约关系,引入了进程同步和进程互斥的概念。进程同步是指为完成某种任务而建立的两个或多个进程,这些进程因为需要在某些位置上协调它们的工作次序而等待、传递信息所产生的制约关系。进程间的直接制约关系源于它们之间的相互合作。虽然多个进程可以共享系统中的各种资源,但其中许多资源一次只能为一个进程所用,我们将一次仅允许一个进程使用的资源称为临界资源。当一个进程进入临界区使用临界资源时,另一个进程必须等待,当占用临界资源的进程退出临界区后,另一进程才允许去访问此临界资源,这就是进程互斥。在每个进程中,访问临界资源的那段代码称为临界区。为了保证临界资源的正确使用,可把临界资源的访问过程分成4个部分:

  • 进入区:为了进入临界区使用临界资源,在进入区要检查可否进入临界区,若能进入临界区,则应设置正在访问临界区的标志,以阻止其它进程同时进入临界区。
  • 临界区:进程中访问临界资源的那段代码。
  • 退出区:将正在访问临界区的标志清除。
  • 剩余区:代码中的其余部分。

实现进程互斥的软件实现方法

软件实现方法是指在进入区设置并检查一些标志来标明是否有进程在临界区中,若已有进程在临界区,则在进入区通过循环检查进行等待,进程离开临界区后则在退出区修改标志。

在这里插入图片描述

实现进程互斥的硬件实现方法

在这里插入图片描述

互斥锁

互斥锁是解决进程互斥最简单的工具,一个进程在进入临界区时应获得锁;在退出临界区时释放锁。函数acquire()获得锁,而函数release()释放锁。每个互斥锁有一个布尔变量available,表示锁是否可用。如果锁是可用的,调用acqiure()会成功,且锁不再可用。当一个进程试图获取不可用的锁时,会被阻塞,直到锁被释放。acquire()release()的执行必须是原子操作,因此互斥锁通常采用硬件机制来实现。

//用C语言描述的互斥锁
acquire(){
 while(!available);
 available=false;
}
release(){
 available=true;
}

互斥锁违反了让权等待原则。

信号量

信号量其实就是一个变量(可以是一个数也可以是一个复杂的结构),可以用一个信号量来表示系统中某种资源的数量。用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而很方便的实现了进程互斥和进程同步。信号量只能通过wait(S)signal(S)原语访问,这两个原语常称为P、V操作。

整型信号量

整型信号量被定义为一个用于表示资源数目的整型量S,用C语言可描述为:

wait(S){
	while(S<=0);
	S=S-1;
}
signal(S){
	S=S+1;
}

记录型信号量

管程

系统中的各种硬件资源和软件资源,均可用数据结构抽象地描述其资源特性,即用少量信息和对资源所执行的操作来表征该资源,而忽略它们的内部结构和实现细节。利用共享数据结构抽象地表示系统中的共享资源,而把对该数据结构实施的操作定义为一组过程。进程对共享资源的申请、释放等操作,都通过这组过程来实现,这组过程还可以根据资源情况,或接受或阻塞进程的访问,确保每次仅有-一个进程使用共享资源,这样就可以统一管理对共享资源的所有访问,实现进程互斥。这个代表共享资源的数据结构,以及由对该共享数据结构实施操作的一组过程所组成的资源管理程序,称为管程(monitor)。管程定义了一个数据结构和能为并发进程所执行(在该数据结构上)的一组操作,这组操作能同步进程和改变管程中的数据。

monitor Demo{//定义一个名为Demo的管程
 //定义一个共享数据结构,对应系统中的某种共享资源
 共享数据结构S;
 //对共享数据结构初始化
 init_code(){
  ...
 }
 //申请一个资源
 take_away(){
  对共享数据机构x的一系列处理
 }
 //归还一个资源
 give_back(){
  对共享数据机构x的一系列处理
 }
}

当一个进程进入管程后被阻塞,直到阻塞的原因解除时,在此期间,如果该进程不释放管程,那么其它进程无法进入管程。为此,将阻塞原因定义为条件变量condition。通常,一个进程被阻塞的原因可以有多个,因此在管程中设置了多个条件变量。每个条件变量保存了一个等待队列,用于记录因该条件变量而阻塞的所有进程,对条件变量只能进行两种操作,即waitsignal

  • x.wait:当x对应的条件不满足时,正在调用管程的进程调用x.wait将自己插入x条件的等待队列,并释放管程。此时其它进程可以使用该管程。
  • x.signal: x对应的条件发生了变化,则调用x.signal,唤醒一个因x条件而阻塞的进程。
monitor Demo {

 共享数据结构s;
 condition X;
 //定义一个条件变量x
 
 init_ code() { 
  ...
 }
 
 take_away() {
  if(S<=0) {
   x.wait();//资源不够,在条件变量x上阻塞等待
  }
  资源足够,分配资源,做一系列相应处理;
 }
 give_back(){
  归还资源,做一系列相应处理;
  if (有进程在等待){
   x.signal; / /唤醒一个阻塞进程
  } 
 }
  • 28
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

亻乍屯页女子白勺

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值