4、进程的描述与控制

进程管理

进程的定义和特征

为了能使程序并发执行,并且可以对并发执行的程序加以描述和控制,人们引入了"进程"的概念。

为了使参与并发执行的每个程序(含数据)都能独立地运行,在操作系统中必须为之配置一个专门的数据结构,称为进程控制块(Process Control Block,PCB)。系统利用PCB来描述进程的基本情况和活动过程,进而控制和管理进程。这样,由程序段、数据段和PCB三部分便构成了进程实体(又称进程映像)。

一般情况下,我们把进程实体就简称为进程,例如所谓创建进程,实质上就是创建进程实体中的PCB;而撤销进程,实质上就是撤销进程的PCB。

(严格来说,进程实体和进程并不一样,进程实体是静态的,进程则是动态的。)

我们可以把传统OS中的进程定义为:进程是进程实体的运行过程,是系统进行资源分配和调度的一个独立单位。

进程的特征

进程和程序是两个截然不同的概念,除了进程具有程序所没有的PCB结构外,还具有下面一些特征:

  • 动态性:进程的实质是进程实体的运行过程。因此,动态性就是进程的最基本的特征;
  • 并发性:是指多个进程实体同存于内存中,且能在一段时间内同时运行。而程序(没有建立PCB)是不能参与并发执行的;
  • 独立性:独立性是指进程实体是一个能独立运行、独立获得资源和独立接受调度的基本单位。
  • 异步性:是指进程是按异步方式运行的,即按各自独立的、不可预知的速度向前推进。

进程的状态与转换

进程的三种基本状态

(1)就绪(Ready)状态

这是指进程已处于准备好运行的状态,即进程已分配到除CPU以外的所有必要资源,只要再获得CPU,便可立即执行。如果系统中有许多处于就绪状态的进程,通常将它们按一定的策略(优先级策略)排成一个队列,称该队列为就绪队列;

(2)执行(Running)状态

这是指进程已获得CPU,其程序正在执行的状态。在多处理机系统中,则有多个进程处于执行状态;

(3)阻塞(Block)状态

这是指正在执行的进程由于发生某事件(如IO请求,申请缓冲区失败)暂时无法继续执行的状态。此时引起进程调度,OS把处理机分配给另一个就绪进程,而让受阻进程处于暂停状态,一般将这种暂停状态称为阻塞状态。

通常系统将处于阻塞状态的进程也排成一个队列,称该队列为阻塞队列。

实际上,在较大的系统中,为了减少队列操作的开销,提高系统效率,根据阻塞原因的不同,会设置多个阻塞队列。

三种基本状态的转换

在这里插入图片描述

为了满足进程控制块对数据及操作的完整性,通常在系统中又为进程引入了两种常见的状态:创建状态和终止状态。

(4)创建状态

创建进程是一个很复杂的过程,如首先由进程申请一个空白PCB,并向PCB中填写用于控制和管理进程的信息;然后为该进程分配运行时所必须的资源;最后,把该进程转入就绪状态并插入就绪队列之中。但是如果此时进程所需的资源无法得到满足,比如系统尚无足够的内存使进程无法装入其中,此时创建工作尚未完成,进程不能被调度运行,于是把此时进程所处的状态称为创建状态。

(5)终止状态

首先是等待操作系统进行善后处理,最后将其PCB清零,并将PCB空间返还系统。

挂起操作

与挂起操作对应的是激活操作。

引入挂起原语Suspend和激活原语Active后,在它们的作用下,进程将可能发生以下几种状态的转换:

  • 活动就绪 -> 静止就绪。当进程处于未被挂起的就绪状态,称为活动就绪状态,此时进程可以接受调度。当用挂起原语Suspend将该进程挂起后,该进程变转变为静止就绪状态,不再被调度执行;
  • 活动阻塞 -> 静止阻塞。当进程处于未被挂起的阻塞状态,称为活动阻塞状态。当用Suspend原语将它挂起后,进程便转变为静止阻塞状态。处于该状态的进程在其所期待的事件出现后,它将从静止阻塞变为静止就绪状态;
  • 静止就绪 -> 活动就绪。处于静止就绪状态的进程若用激活原语Active激活后,该进程转变为活动就绪状态;
  • 静止阻塞 -> 活动阻塞。处于静止阻塞状态的进程若用激活原语Active激活后,该进程转变为活动阻塞状态。

在这里插入图片描述

进程控制块PCB

PCB的作用是使一个程序成为能在多道程序环境下独立运行的基本单位,一个能与其他进程并发执行的进程。

  • 作为独立运行基本单位的标志;
  • 能实现间断性运行方式;
  • 提供进程管理所需要的信息;
  • 提供进程调度所需要的信息;
  • 实现与其他进程的同步与通信;

在进程控制块中,主要包括下述四个方面的信息。

  • 进程标识符
  • 处理机状态
    • 当进程被切换时,处理机状态信息都必须保存在相应的PCB中,以便在该进程重新执行时能再从断点继续执行;
  • 进程调度信息
  • 进程控制信息

进程控制块的组织方式

在一个系统中,通常可拥有数十个、数百个、甚至数千个PCB。

目前常用的组织方式:

  • 线性方式
    • 所有的PCB都组织在一张线性表中;
  • 链接方式
    • 具有相同状态进程的PCB链接成一个队列
  • 索引方式

进程控制

操作系统内核

进程控制是进程管理中最基本的功能,主要包括创建新进程、终止已完成的进程、置为阻塞状态、状态转换等功能。

进程控制一般是由OS的内核中的原语来实现的。

通常将一些与硬件紧密相关的模块(如中断处理程序等)、各种常用设备的驱动程序以及运行频率较高的模块(如时钟管理、进程调度等),都安排在紧靠硬件的软件层次中,将它们常驻内存,即通常被称为的OS内核。

相对应的是,为了防止OS本身及关键数据(如PCB等)遭受应用程序的破坏,通常也将处理机的运行状态分成系统态和用户态两种。

系统态,又称管态,也称为内核态。它具有较高的特权,能执行一切指令,访问所有寄存器和存储区。

用户态,又称目态,它是具有较低特权的执行状态,仅能执行规定的指令,访问指定的寄存器和存储区。

一般情况下,应用程序只能在用户态运行,不能去执行OS指令及访问OS区域。

大部分OS内核都包含了以下两大方面的功能:

1、支撑功能

  • 中断处理
  • 时钟管理
    • 在时间片轮转调度中,每当时间片用完时,便由时钟管理产生一个中断信号,促使调度程序重新调度。
  • 原语操作
    • 所谓原语(Primitive),就是由若干条指令组成的,用于完成一定功能的一个过程。它与一般过程的区别在于:它们是"原子操作"。所谓原子操作是指,一个操作中的所有动作要么全做,要么全不做。是一个不可分割的基本单位。
    • 因此,原语在执行过程中不允许被打断。原子操作在系统态下执行,常驻内存。
    • 在内核中存在许多原语,如用于实现进程同步的原语。

2、资源管理功能

  • 进程管理
  • 存储器管理
  • 设备管理

进程的创建

在OS中,允许一个进程创建另外一个进程,通常把创建进程的进程称为父进程,把被创建的进程称为子进程。

子进程可以继续创建更多的孙进程,由此便形成了一个进程的层次结构。

子进程可以继承父进程所拥有的资源,当子进程被撤销时,应将其从父进程那里获得的资源归还给父进程,此外,在撤销父进程时,也必须同时撤销其所有的子进程。

为了标识进程之间的家族关系,在PCB中设置了家族关系表项。

进程图

用一条由进程Pi指向进程Pj的有向边来描述它们之间的父子关系。

在系统中每当出现了创建新进程的请求后,OS便调用进程创建原语Creat按下述步骤创建一个新进程:

  • 申请空白PCB;
  • 为新进程分配其运行所需的资源;
  • 初始化进程控制块(PCB)
    • 初始化标识信息,将系统分配的标识符和父进程标识符填入新PCB中;
    • 初始化处理机状态信息,程序计数器指向程序的入口地址;
    • 初始化处理机控制信息,将进程的状态设置为就绪状态或者静止就绪状态,对于优先级,通过是将它设置为最低优先级,除非用户显式提出高优先级要求;
  • 如果进程就绪队列能够接纳新进程,便将新进程插入就绪队列

进程的终止

(1)正常结束

(2)异常结束

常见的异常事件:

  • 越界错:程序所访问的存储区,已越出该进程的区域;
  • 保护错:进程试图去访问一个不允许访问的资源或文件;
  • 非法指令;
  • 运行超时;
  • 等待超时;
  • 算术错误;
  • IO故障;

(3)外界干预

终止过程:

  • 根据被终止进程的标识符,从PCB集合中检索出该进程的PCB,从中读取该进程的状态;
  • 若被终止进程正处于执行状态,应立即终止该进程的执行,并置调度标志为真,用于指示该进程被终止后应重新运行调度;
  • 若该进程还有子孙进程,还应将其所有子孙进程也予以终止,以防它们成为不可控的进程;
  • 归还资源给父进程或OS;
  • 将被终止进程PCB从所在队列或链表中移除;

进程阻塞与唤醒

有下述几类事件会引起进程阻塞或被唤醒:

  • 向系统请求共享资源失败:例如进程请求使用打印机,由于系统已经将打印机分配给其他进程,已无可以分配的打印机,这时进程只能被阻塞;在其他进程释放出打印机后,请求进程才被唤醒;
  • 等待某种操作的完成:当进程启动某种操作后,如果该进程必须在该操作完成之后才可以继续执行,则应先将该进程阻塞起来,以等待操作完成;IO操作;在IO完成后,由中断处理程序将该进程唤醒;
  • 新数据尚未到达,对于相互合作的进程,如果一个进程需要先获得另一进程提供的数据才能对该数据进行处理,只要其所需的数据尚未到达,进程便只有阻塞;一旦进程A把数据输入完毕,便可去唤醒进程B;
  • 等待新任务的到达,例如在网络环境中的发送进程,其主要任务是发送数据包,若已有的数据包已全部发送完毕,而又无新的数据包发送,这是发送进程将把自己阻塞起来;仅当有新的数据包到达时,才将发送进程唤醒。

进程阻塞过程:

如果发生了上述事件,进程便通过调用阻塞原语block将自己阻塞,由此可见,阻塞是进程自身的一种主动行为。

进程控制块中的执行改为阻塞,并将PCB插入阻塞队列。如果系统中设置了因不同事件而阻塞的多个阻塞队列,则应将本进程插入到具有相同事件的阻塞队列。

保留被阻塞进程的处理机状态。

进程唤醒过程:

当被阻塞进程所期待的事件发生时,比如数据到达,IO完成,则由有关进程(比如提供数据的进程)调用唤醒原语wakeup,将等待该事件的进程唤醒。

把被阻塞进程从等待该事件的阻塞队列中移出,将其PCB的状态由阻塞改为就绪,然后将该PCB插入就绪队列。

注意:block原语和wakeup原语是一对作用刚好相反的原语,在使用他们时,必须成对使用。

即,如果在某进程中调用了阻塞原语,则必须在与之合作的进程中安排一条相应的唤醒原语,以便能唤醒被阻塞进程,否则,阻塞进程将会因不能被唤醒而永久的处于阻塞状态。

进程同步

基本概念:对多个相关进程在执行次序上进行协调,使并发执行的诸进程之间能按照一定的规则共享系统资源。

1、临界资源

许多硬件资源,如打印机,磁带机,都属于临界资源,诸进程间应采取互斥方式,实现对这种资源的共享。

2、临界区

在每个进程中访问临界资源的那段代码称为临界区。

while (true) {
	进入区
	临界区
	退出区
	剩余区
}

3、同步机制应遵循的规则

  • 空闲让进:当无进程处于临界区,表明临界资源处于空闲状态,应允许一个请求进入临界区的进程立即进入自己的临界区,以便有效的利用资源;
  • 忙则等待:当已有进程进入临界区时,表明临界资源正在被访问,因为其他试图进入临界区的进程必须等待,以保证对临界资源的互斥访问;
  • 有限等待:对要求访问临界资源的进程,应保证在有限时间内能进入自己的临界区,以免陷入死等状态;
  • 让权等待:当进程不能进入自己的临界区时,应立即释放处理机,以免进程陷入忙等状态。

4、硬件同步机制

  • 关中断:进程在临界区执行期间,计算机系统不响应中断,从而不会引发调度,也就不会发生进程或线程切换;
  • 利用Test-and-Set指令实现互斥
  • 利用Swap指令

5、信号量机制

信号量其实就是一个变量(可以是一个整数、也可以是更复杂的记录型变量),可以用一个信号量来表示系统中某种资源的数量。

原语是一种特殊的程序段,其执行只能一气呵成,不可被中断,原语是由关中断/开中断指令实现的。

用户进程可以通过使用操作系统提供的一对原语来对信号量进行操作,从而方便的实现了进程互斥、进程同步。

一对原语:wait(S)原语和signal(S)原语,可以把原语理解为我们的函数,函数名分别为wait和signal,括号中的信号量S就是函数调用时传入的一个参数。

wait、signal原语简称P、V操作,因此,常常把wait(S)、signal(S)两个操作分别写为P(S)、V(S)。

6、整型信号量

用一个整数型的变量作为信号量,用来表示系统中某种资源的数量。

在这里插入图片描述

在这里插入图片描述

在整型信号量机制中的wait操作,只要是信号量<=0,就会不断得测试,因此,该机制不满足"让权等待"原则,会发生"忙等"。

7、记录型信号量

在信号量机制中,除了需要一个用于代表资源数目的整型变量vlaue外,还应增加一个进程链表指针list,用于链接上述的所有等待进程。

在这里插入图片描述

对于signal中的if(S.value <= 0)的理解:

当释放了一个资源后,S.value <= 0,说明在该信号量链表中仍有等待该资源的进程被阻塞,所以还应调用wakeup原语。

假设S.value初始值为1,P1线程执行wait,进入进入区,S.value = 0,P2线程执行wait,S.value = -1,进入阻塞链表,P1线程执行完毕,执行signal,S.value = 0,if (S.value <= 0) ,则需要唤醒P2线程。if (S.value < 0)返回false,P2线程使用资源。

8、利用信号量机制实现进程互斥

为了使多个进程能互斥地访问某临界资源,只需为该资源设置一个互斥信号量mutex,并设其初始值为1,然后将各个进程访问该资源的临界区CS置于wait(mutex)和signal(mutex)操作之间即可。

设mutex为互斥信号量,其初值为1,取值范围(-1,0,1),当mutex=1时,表示两个进程都未进入需要互斥的临界区;当mutex = 0时,表示有一个进程进入临界区运行,另外一个必须等待,挂入阻塞队列;当mutex = -1,表示有一个进程正在临界区运行,另一个因等待而阻塞在信号量队列中,需要被当前已在临界区运行的进程退出时唤醒。

semaphore mutex = 1;
Pa() {
    while (1) {
        wait(mutex);
        临界区;
        signal(mutex);
        剩余区;
    }
}

Pb() {
    while (1) {
        wait(mutex);
        临界区;
        signal(mutex);
        剩余区;
    }
}

经典进程的同步问题

1、生产者消费者问题

利用记录型信号量解决生产者消费者问题

假定在生产者和消费者之间的公用缓冲池中具有n个缓冲区,这时可以利用互斥信号量mutex实现诸进程对缓冲池的互斥使用;利用信号量empty和full分别表示缓冲池中空缓冲区和满缓冲区的数量;

只要缓冲区未满,生产者便可将消息送入缓冲池;只要缓冲池未空,消费者便可从缓冲池中取走一个消息。

在这里插入图片描述

在这里插入图片描述

P = wait

V = signal

P(mutex) 和 V(mutex) 实现进程的互斥访问。

P(empty) P(full) V(empty) V(full) 实现进程的同步访问。

不可颠倒上面的顺序。实现互斥的P操作必须在实现同步的P操作之后。

两个V操作的顺序可以交换。

2、哲学家进餐问题

在这里插入图片描述

假如五位哲学家同时饥饿而各自拿起左边的筷子时,就会使五个信号量chopstick均为0,当他们再试图去拿右边的筷子时,都将因为无筷子可拿而无限期地等待。

对于这样的死锁问题,可采取以下几种解决办法:

  • 至多只允许有四位哲学家同时去拿左边的筷子,最终能保证至少有一位哲学家能够进餐,并在用毕后能释放出他用过的两只筷子,从而使更多的哲学家进餐;
  • 仅当哲学家的左右两只筷子都可用时,才允许他拿起筷子;

在这里插入图片描述

上面的方法:当两边筷子都可用时,也不一定能拿到筷子。

哲学家问题的关键在于解决进程死锁。

这些进程之间只存在互斥关系,但是与之前接触到的互斥关系不同的是,每个进程都需要同时持有两个临界资源,因此就有"死锁"的隐患。

3、读者-写者问题

在这里插入图片描述

为实现Reader和Writer进程间在读/写时的互斥而设置了一个互斥信号量wmutex,另外再设置一个整型变量readcount表示正在读的进程 数目,又因为readcount是一个可被多个Reader进程访问的访问的临界资源,因此,也应该为它设置一个互斥信号量rmutex。

semaphore rmutex = 1, wmutex = 1;
int readcount = 0;
void reader() {
	do {
		wait(rmutex);
		if (readcount == 0) 
			wait(wmutex);
			//当第一个读进程进来时,应该上锁,以防止写进程进来
		readcount++;
		signal(rmutex);
		//多个读进程访问,只可以上一把锁,同时只能有一个进程修改readcount的值
		...
		read operation
		...
		wait(rmutex);
		readcount--;
		if (readcount == 0) 
			//当还有读线程时,暂时不能放开锁
			signal(wmutex);
		signal(rmutex);
	} while (true);
}

void writer() {
	do {
		wait(wmutex);
		write operation;
		signal(wmutex);
	} while (true);
}

进程通信

进程通信是指进程之间的信息交换。由于进程的互斥和同步,需要在进程间交换一定的信息,故有人也将它们归为进程通信。但是只能把它们称为低级进程通信。

进程通信的类型

(1)共享存储器系统

在共享存储器系统中,相互通信的进程共享某些数据结构或共享存储区,进程之间能够通过这些空间进行通信。

  • 基于共享数据结构的通信方式

如在生产者-消费者问题中的有界缓冲区,通信效率低下,属于低级通信;

  • 基于共享存储区的通信方式

为了传输大量数据,在内存中划出了一块共享存储区域,诸进程可通过对该共享区的读写交换信息,实现高级通信。

(2)管道通信系统

所谓"管道",是指用于连接一个读进程和一个写进程以实现他们之间通信的一个共享文件,又名pipe文件。

向管道(共享文件)提供输入的发送进程(写进程)以字符流形式将大量的数据送入管道;而接受管道输出的接收进程(读进程)则从管道中接收(读)数据。

在这里插入图片描述

由于发送进程和接收进程是利用管道进程通信的;故又称管道通信。

管道只能采用半双工通信,某一时间段只能实现单向的传输。

管道机制必须提供以下三方面的协调能力:

  • 互斥:一方在读写时,另一方必须等待;
  • 同步:当输入进程把一定数量的数据写入pipe时,便去睡眠等待,直到读进程取走数据;
  • 确定对方是否存在

(3)消息传递系统

在该机制中,进程不必借助任何共享存储区或数据结构,而是以格式化的消息为单位,将通信的数据封装在消息中,并利用操作系统的一组通信命令(原语)在进程之间进程消息传递。

在计算机网络中,消息又称为报文,在微内核操作系统中,微内核与服务器之间的通信无一例外都是采用了消息传递机制。

  • 直接通信方式:发送进程利用OS原语,直接把消息发送给目标进程;
  • 间接通信方式:发送进程和接收进程,都通过共享中间实体(称为邮箱)的方式进行消息的发送和接收,完成进程间的通信。

(4)客户机-服务器系统

前面所述的共享内存、消息传递等技术,虽然也可以用于实现不同计算机间进程的双向通信,但客户机-服务器系统的通信机制,在网络环境的各种应用领域已成为当前主流的通信实现机制。

  • 套接字

一个套接字就是一个通信标识类型的数据结构,包含了通信目的的地址,通信使用的端口号,通信网络的传输层协议,进程所在的网络地址,以及为客户服务器程序提供的不同系统调用,是进程通信和网络通信的基本构件。

文件型;

网络型;

通信双方的进程运行在不同主机的网络环境下,被分配了一对套接字,一个属于接收进程(服务端),一个属于发送进程(客户端)。

一般地,发送进程发出连接请求,随机申请一个套接字,主机为之分配一个端口,与该套接字绑定,不再分配给其他进程。接收进程拥有全局公认的套接字和指定的端口(如ftp服务器监听21端口,http服务器监听80端口),并通过监听端口等待客户请求。

  • 远程过程调用
  • 远程方法调用

远程过程调用(Remote Procedure Call)是一个通信协议,用于通过网络连接的系统。

该协议允许运行于一台主机(本地)系统上的进程调用另一台主机(远程)系统上的进程,而对程序员表现为常规的过程调用。如果涉及的软件采用面向对象编程,那么远程过程调用亦可称为远程方法调用。

为了使远程过程调用看上去和本地过程调用一样,RPC引入了一个存根(stub)的概念。

消息传递通信的实现方式

  • 直接消息传递系统
  • 信箱通信

直接消息传递系统的实例:消息缓冲队列通信机制。

线程的基本概念

如果说在OS中引入进程的目的是为了使多个程序能并发执行,那么,在OS中引入线程,则是为了减少程序在并发执行时所付出的时空开销,使OS具有更好的并发性。

进程的两个基本属性:

  • 拥有资源的独立单位
  • 可独立调度和分派的基本单位

程序并发执行所需的时空开销:

  • 创建进程
  • 撤销进程
  • 进程切换

线程—作为调度和分派的基本单位。

线程与进程的比较

由于线程具有许多传统进程所具有的特征,所以又称之为轻型进程。

(1)调度的基本单位

在传统OS中,每次调度时都需要进行上下文切换,开销较大。引入线程后,切换代价远低于进程。在同一进程中,线程的切换不会引入进程的切换,但从一个进程中的线程切换到另一个进程中的线程时,必然就会引入进程的切换;

(2)并发性

在引入线程的OS中,不仅进程之间可以并发执行,而且在一个进程中的多个线程之间也可以并发执行。同样,不同进程的线程也能并发执行。

例如,在网页浏览器中,一个线程来显示图像或文本,另一个线程用于从网络上接收数据。

(3)拥有资源

进程可以拥有资源,但是线程本身并不拥有系统资源,而是仅有一点必不可少的资源。比如,在每个线程中都应具有一个用于控制线程运行的线程控制块TCB、用于指示被执行指令序列的程序计数器、虚拟机栈(局部变量表、操作数栈、返回地址)。

线程除了拥有自己的少量资源外,还允许多个线程共享该进程所拥有的资源。

(4)独立性

在同一进程中的不同线程之间的独立性比不同进程之间的独立性低得多。

(5)系统开销

在创建或撤销进程时,OS为此付出的开销,明显大于线程创建或撤销所付出的代价。

类似的,线程的切换代价也远比进程切换的代价低。

线程控制块TCB

线程控制块通常包含这样几项:

(1)线程标识符

(2)一组寄存器,程序计数器PC等

(3)线程运行状态

(4)优先级

(5)线程专有存储区

(6)堆栈指针:每个线程设置一个堆栈,用来保存局部变量以及返回地址等,相应的,在TCB中,也要设置两个指向堆栈的指针:指向用户自己堆栈的指针和执行核心栈的指针,前者是当程序运行在用户态时,使用用户自己的用户栈来保存局部变量和返回地址,后者是指当线程运行在核心态时使用系统的核心栈。

线程的实现方式

1、内核支持线程KST(Kernel Supported Threads)

在OS中的所有进程,无论是系统进程还是用户进程,都是在操作系统内核的支持下运行的,是与内核紧密相关的。而内核支持线程KST同样也是在内核的支持下运行的,它们的创建、阻塞、撤销和切换,也都是在内核空间实现的。

为了对内核线程进行控制和管理,在内核空间也为每一个内核线程设置了一个线程控制块。

缺点:

对于用户的线程切换而言,其模式切换的开销较大,在同一个进程中,从一个线程切换到另一个线程,需要从用户态转到核心态进行,这是因为用户进程的线程在用户态运行,而线程调度和管理在内核实现,系统开销较大。

在这里插入图片描述

2、用户级线程ULT(User Level Threads)

用户级线程是在用户空间实现的,对线程的创建、撤销、同步和通信等功能,都无需内核的支持,即用户级线程是与内核无关的。

在一个系统中的用户级线程的数目可以达到数百个至数千个。由于这些线程的任务控制块都是设置在用户空间,而线程所执行的操作也无需内核的帮助,因而内核完全不知道用户级线程的存在。

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

对于设置内核级线程的系统,调度则是以线程为单位。

在这里插入图片描述

3、组合方式

由于用户级线程和内核支持线程连接方式的不同,从而形成了三种不同的模型:多对一模型、一对一模型和多对多模型。

  • 多对一模型

多个用户线程映射到一个内核支持线程。这些用户线程一般属于一个进程,运行在该进程的用户空间,对这些线程的调度和管理也是在该进程的用户空间中完成。仅当用户线程需要访问内核时,才将其映射到一个内核控制线程,但每次只允许一个线程进程映射。

缺点:如果一个线程在访问内核时发生阻塞,则整个进程都会被阻塞。此外,在任一时刻,只有一个线程能够访问内核,多个线程不能同时在处理机上运行。

  • 一对一模型

一个用户级线程映射到一个内核支持线程。

优点:当一个线程阻塞时,允许调度另一线程运行。

缺点:每创建一个用户线程,相应地就要创建一个内核线程,开销较大。

  • 多对多模型

许多用户线程映射到同样数量或者更少数量的内核线程上。

在这里插入图片描述

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值