第二章 进程管理--笔记

进程的基本概念


程序的顺序执行的特征:

(1)顺序性(2)封闭性(3)可再现性


程序的并发执行的特征:

(1)间断性(2)失去封闭性(3)不可再现性


进程实体(进程映像):程序、数据、PCB、栈


为了让程序能够并发才建立进程,没有建立PCB的程序不是进程,更不能并发执行。创建进程就是创建进程的PCB,撤销进程就是撤销进程的PCB


进程的三状态模型(就绪态、执行态、阻塞态)


引入挂起状态后的五状态模型(活动就绪态、静止就绪态、活动阻塞态、静止阻塞态、执行态)

“活动”--没有挂起,“静止”--挂起


引入创建状态和中止状态后的七状态模型活动就绪态、静止就绪态、活动阻塞态、静止阻塞态、执行态、创建态、终止态


进程控制块(PCB)


作用:

       记录了用于描述进程的当前情况以及控制进程运行的全部信息


过程:

       当OS要调度某进程执行时,要从该进程的PCB中查出当前状态和优先级;

       在调度到某进程后,要根据其PCB中所保存的处理器状态信息,设置该进程恢复运行的现场,并根据其PCB中的程序和数据的内存地址,找到其程序和数据;

       进程在执行过程中,当需要和与之合作的进程实现同步、通信或访问文件时,也都需要访问PCB;当进程由于某种原因而暂停执行时,又须将其断点的处理器环境保存在PCB中。


内容:

(1)进程标识符:内部标识符(纯数字,给系统看)、外部标识符(字母、数字,创建者提供)

(2)处理器状态:处理器的寄存器中的内容

(3)进程调度信息:与进程调度和进程对换有关的信息,如1)进程状态  2)进程优先级  3)事件 等

(4)进程控制信息:

                    1)程序和数据的地址 

                    2)进程同步和通信机制,如信号量  

                    3)资源清单(除CPU以外的)

                    4)指向本进程所在队列的下一个进程的PCB的首地址


组织方式:

(1)链接方式(2)索引方式


进程控制:

基本概念:

      进程管理中最基本的概念,包含进程的创建、终止、阻塞与唤醒、挂起与激活。


进程的创建:

       引起进程创建的事件:

     (1)用户登录(分时系统中为终端用户创建进程)

     (2)作业调度(调度到某作业时,为它创建进程、分配资源(除CPU)、插入到就绪队列中)

     (3)提供服务(进程请求OS为它创建一个新进程完成任务)

     (4)应用请求(进程自己为自己创建一个子进程)


       进程的创建:(primitive:Create)

     (1)申请PCB,获得唯一数字标识符;

     (2)分配资源(主要是为程序、数据、用户栈分配空间);

     (3)初始化PCB:标识符、处理器状态信息(PC指向程序入口地址,st指向栈顶)、处理器控制信息(优先级、进               程状态)

     (4)插入到就绪队列中


进程的终止:

       引起进程终止的事件:

     (1)正常结束

     (2)异常结束(越界、访问权限、超时、算术运算......)

     (3)外界干预(OS或人为,父进程终止,父进程请求终止子进程......)


       进程的终止:(primitive:未知)

     (1)获取PCB中的进程状态

     (2)若处于执行态,则终止进程,设调度标志为真

     (3)终止所有后代进程

     (4)将自己和后代进程的所有资源归还给父进程 或 OS

     (5)将PCB从所在链表移出


进程的阻塞与唤醒:

       引起进程阻塞和唤醒的事件:

     (1)请求系统服务(如printer)

     (2)启动某种操作(如I/O)

     (3)等待数据或请求

 

      进程的阻塞:(primitive:block)

      进程无法继续执行,把自己阻塞。若还在执行,则停止执行并把PCB中的状态改为阻塞态,保留处理器上下文,插入到对应事件的阻塞队列。调度程序把处理器分配给下一个就绪进程,按新进程的PCB设置处理器上下文。


       进程的唤醒:(primitive:wakeup)

       将被阻塞的进程从阻塞队列中移出,PCB中的状态改为就绪,并加入就绪队列。


进程的挂起与激活:

       进程的挂起:(primitive:suspend)

      进程调入外存, 活动就绪-》静止就绪;活动阻塞-》静止就绪;若被挂起的进程正在执行,转向调度程序调度


      进程的激活:(primitive:active)      

      进程调入内存,精致就绪-》活动就绪;静止阻塞-》活动阻塞;转向调度程序调度
      

进程同步


进程同步的基本概念:

       对多个相关进程在执行次序上进行协调,并发的进程之间能够进行资源共享和相互合作,使程序的执行具有可再现性。

1. 两种形式的制约关系

(1)直接相互制约--源于进程间的合作
(2)间接相互制约--源于资源共享

2. 临界资源

诸进程间应用采用互斥共享的方式,实现对临界资源的访问。

以生产者-消费者问题为例,其中的counter 应作为临界资源处理(详情参考[1] P48~49)


3. 临界区

临界区(critical section)--进程中访问临界资源的那段代码
若能保证诸进程互斥地进入自己的临界区,就能保证诸进程对临界资源的互斥访问。

进入区(entry section)--临界区前的检查代码,用于检测是否有别的进程正在访问临界资源
退出区(exit section)--进程完成临界区的代码后,用于把临界资源 “正在被访问的标志” 设为 “未被访问的标志”

临界区、进入区、退出区 以外的代码--剩余区(remainder section)

临界区的互斥访问(进程同步的一部分,另一部分未进程间的合作)应该遵循的规则:
1. 空闲让进 2. 忙则等待 3. 有限等待 4. 让权等待

实现临界区互斥的基本方法:

硬件方法:


中断禁用(单处理器)、专用机器指令(多处理器)

中断禁用:因为在单处理器机器中,一次只能有一个进程在执行,为保证互斥,只用保证进程不被中断就行。
专用机器指令:引入原子操作


软件方法:

信号量、管程

信号量机制:


资源共享的概念:
在这里,“共享”指的是 “大家都需要用”,而不是 “大家可以同时用”。


整型信号量:
       特点:一次分配/回收一个单位的资源,只允许一个进程访问资源;一种临界资源,只有一份(initS = 1)
       代码:
wait(S): while S<=0 do no-op;
	S:=S-1;
signal(S):	S:=S+1;


记录型信号量:
       特点:引入进程阻塞队列L,信号量S的初始值表示“允许同时访问临界资源的进程数”;
                  一种临界资源,多份(initS > 1)
       引入原因:整型信号量中存在忙等待,浪费处理器时间。故改进--去除忙等待,增加阻塞队列。
       补充:为了“让权等待”,而不是忙等待,常用S=1的记录型信号量代替整形信号量
       代码:
type semaphore = record
	value: integer;
	L: list of process;
	end

procedure wait(S)
	var S: semaphore;
	begin
		S.value:=S.value-1;
		if S.value<0 then block(S.L);
	end

procedure signal(S)
	var S: semaphore;
	begin
		S.value:=S.value+1;
		if S.value<=0 then wakeup(S.L);
	end



AND型信号量:
       特点:记录型信号量的拓展;多种资源,每种多份;进程需要的资源要么一下子分配到位,要么一点都不分配。                     n个临界资源对应n个进程阻塞队列;对一种资源仍然一次只能操作一个单位。
       引入原因:记录型信号量中,共享资源的进程越多,死锁发生的可能性越高。
       代码:
Swait(S1,S2, ..., Sn)
	if S1>=1 ... and Sn>=1 then
		for i:=1 to n do
			Si:=Si-1;
		endfor
	else
		把当前进程放入第一个满足条件Si<1的资源Si对应的阻塞队列中,PC设为
		Swait操作的开始
	endif

Ssignal(S1, S2, ..., Sn)
for i:=1 to n do
	Si:=Si+1;
	把Si对应的阻塞队列的中的进程全部释放到就绪队列中
endfor;



信号量集:
       特点:每次可获得或释放多个单位的资源,引入需求 d,下限 t。当资源数量低于某一下限时,不予分配--减                      少了多次少量分配带来的开销。
       引入原因:前面三种信号量,对一种资源,每次操作只能操作一个单位。效率很低(比如多做了许多 if 判断操                                作)
       三种特殊情况:
              (1) Swait(S,d,d):只有一种信号量S,每次需要申请d份资源,少于d时,则不予分配
              (2) Swait(S,1,1):S > 1 -> 记录型信号量; S = 1 -> 整型信号量
              (3) Swait(S,1,0):S >= 1 时,允许多个信号量访问临界资源(多个进程进入临界区),S = 0 时,阻止任何                                             进程访问临界资源
       代码:
Swait(S1,t1,d1 ..., Sn,tn,dn)
	if S1>=t1 ... and Sn>=tn then
		for i:=1 to n do
			Si:=Si-di;
		endfor
	else
		把当前进程放入第一个满足条件Si<ti的资源Si对应的阻塞队列中,PC设为
		Swait操作的开始
	endif

Ssignal(S1,d1, ..., Sn,dn)
for i:=1 to n do
	Si:=Si+di;
	把Si对应的阻塞队列的中的进程全部释放到就绪队列中
endfor;


整型信号量(互斥信号量)的两个应用:

1. 进程互斥

2. 描述各个进程语句间的前驱关系


1. 要实现多个进程对某一资源互斥访问的话,只需为该资源设置一个信号量,初始值为1. 然后,将各个进程的临界区代码放在wait(mutex) (p操作) 和 signal(mutex) (v操作) 之间即可。

示例:(类 pascal 语法作伪代码挺好,但是缩进销魂,还是放图片比较好)



2. 描述前驱关系的话,两个进程P1和P2,它们之中分别有语句S1和S2。这两个进程并发执行,如果想要语句S2在S1之后执行,那么只需设一个互斥信号量a,令其初始值为0. 

P1:  S1; signal(a)

P2:  wait(a); S2


这样就可以了,更复杂的前驱关系(用一张图表示),可以由此拓展,比如一条边设一个信号量就可以了。

详细例题:参考文献[1] P54 --利用信号量实现前驱关系


管程机制:


引入原因:使用信号量的机制后,每个进程需要自备同步操作 (p、v操作 或说 wait(S)、signal(S) 操作),管理起来很麻烦,而且容易导致死锁


管程概念:将计算机的资源映射成数据结构,将资源的请求和释放等操作映射成数据结构上的操作。则共享数据结构与其操作就构成了“管程”(OS的资源管理程序之意)。

严格来讲,管程的组成为:名称、数据结构、数据结构的操作、字段初始化。

进程要访问临界资源的时候,就需要进入该资源对应的管程,每次只允许一个进程进入管程。


管程特点:1. ADT(抽象数据类型)2. 封装(encapsulation)3. 模块化,管程实际上是OS的一个程序模块


管程和进程的区别:

(1)进程定义的是私有数据结构PCB;管程定义的是公共数据结构(别的进程可以进入管程调用数据结构的操作)

(2)进程做顺序执行操作;管程做同步操作和初始化操作

(3)进程的存在是为了并发;管程的存在是为了解决共享资源的互斥访问问题

(4)进程主动工作;管程被动工作(被调用)

(5)进程间能并发执行,管程不能与其调用者并发执行(管程是被调用的模块,当然不能独立执行)

(6)进程有生死,因“创建“而生,因”撤销“而死;而管程无所谓生死,它只是系统的一个模块


管程相对于信号量:自信号量到管程,pv操作并没有消失,而是从各进程中集中到管程里了(实际上是集中到了数据结构的操作方法里)


说了那么多,管程是如何实现多进程共享资源的互斥访问的?--通过条件变量的pv (wait、signal)操作




PROCESS:

      设 (1) 某资源 (2) 条件变量X (3) 因X而阻塞的进程队列

      进程要请求某资源的时候,进入管程,如果因X条件需要被阻塞或挂起,则调用X.wait将自己插到X条件的阻塞队列后,同时释放管程。此时,其他进程可以进入管程,如果新的进程发现X条件发生了变化,则调用X.signal,从阻塞队列中唤醒一个因为X条件而阻塞的进程。若队列为空,则啥也不做 (这和信号量中的signal操作不同,信号量中的signal操作总会改变资源的数目,而管程中条件变量的signal操作却可以啥都不做) 。


       以上,还产生了一个新的问题--当进程B发现条件X变化,唤醒进程A之后,由于B已经在管程里了,而A理应也要进入管程了。这就有几个简单的策略,比如让A等待,B做完事或B因为等待另一条件而阻塞,然后把管程给A;也可以反过来,还可以折衷。




经典的进程同步问题


生产者-消费者问题


信号量解法:

       设在生产者和消费者之间的缓冲池有n个缓冲区,可以利用互斥信号量mutex实现诸进程对缓冲池的互斥使用。利用资源信号量empty、full分别表示缓冲池中空缓冲区和满缓冲区的数量。


1)记录型型信号量解法:

Var mutex, empty, full: semaphore:=1,n,0;
	buffer:array[0,...,n-1] of item;
	in, out: integer:=0, 0;
	begin
		parbegin
            proceducer: begin
                           repeat
                              produce an item nextp;
                              wait(empty);
                              wait(mutex);
                              buffer(in):=nextp;
                              in:=(in+1) mod n;
                              signal(mutex);
                              signal(full);
                           until false;
                           end
              consumer: begin
                           repeat
                              wait(full);
                              wait(mutex);
                              nextc=buffer(out);
                              out:=(out+1) mod n;
                              signal(mutex);
                              signal(empty);
                              consume the item in nextc;
                              until false;
                           end
		parend
	end

关键:应先执行对资源信号量的wait操作,然后再执行对互斥信号量的wait操作,否则可能会引发进程死锁。


2)AND型信号量解法:

可以同时对多种资源作一个单位的操作,代码比1)要简洁一些。

Var mutex, empty, full:semaphore:=1,n,0;
    buffer:array[0,...,n-1] of item
    in out: integer:=0,0;
    begin
         parbegin
            producer: begin
			  repeat
                              produce an item in nextp;
                              Swait(empty,mutex);
                              buffer(in):=nextp;
                              in:=(in+1) mod n;
			      Ssignal(mutex,full);
                          until false;
                      end
            consumer: begin
                          repeat
                              Swait(full,mutex);
                              nextc:=buffer(out);
                              out:=(out+1) mod n;
                              Ssignal(mutex,empty);
                              consume the item in nextc
                          until false;
                      end
         parend
    end


3)管程解法:

建立管程,主要是数据结构的field和operation,定义两个operation: put(item)  生产者通过这个操作把产品放到缓冲池中,利用count来表示缓冲池的产品数目,当count>=n时--缓冲池已满,生产者等待。get(item) 消费者通过这个操作从缓冲池中取出一个产品,当count<=0时,表示缓冲池中没有产品了,消费者等待

建立管程如下:

type producer-consumer=monitor
    Var in,out,count: integer;				//字段 (field)
	    buffer: array[0,...,n-1] of item;		
        notfull, notempty:condition;			//条件变量
        procedure entry put(item)			//put operation
            begin
                if count>=n then notfull.wait;
                buffer(in):=nextp;
		in:=(in+1) mod n;
		count:=count+1;
		if notempty.queue then notempty.signal;
	    end
        procedure entry get(item)			//get operation
            begin
	        if count<=0 then notempty.wait;
		nextc:=buffer(out);
		out:=(out+1) mod n;
		count:=count-1;
		if notfull.queue then notfull.signal;
	    end
        begin in:=out:=0;				//字段 (field) 初始化
	count:=0;
    end


在生产者和消费者的进程中调用管程:

producer: begin
				repeat
					produce an item in nextp;
					PC.put(item);
				until false;
		  end

consumer: begin
				repeat
					PC.get(item);
					consume the item in nextc;
				until false;
		  end


哲学家进餐问题


五哲学家共用一圆桌,只有五根筷子,分处于每人左右手边。要使每个哲学家都能用两根筷子吃饱饭

1)记录型信号量解法:
Var chopstick: array[0,...,4] of semaphore;
    repeat
	  wait(chopstick[i]);
	  wait(chopstick[(i+1)mod 5]);
	  ...
	  eat;
	  ...
	  signal(chopstick[i]);
  	  signal(chopstick[(i+1)mod 5]);
	  ...
	  think;
    until false;

但是,上述解法有可能产生死锁,比如每个哲学家都拿起来了自己左手边的筷子。大家都在等待拿右手边的筷子,全部都被阻塞了。

可以使用AND信号量机制来解决这个问题--要么分配到两根筷子后进餐,要么一根都不拿干等着

2)AND型信号量解法:
Var chopstick array of semaphore:=(1,1,1,1,1);
	process i
		repeat
			think;
			Swait(chopstick[i],chopstick[(i+1)mod 5]);
			...
			eat;
			...
			Ssignal(chopstick[i],chopstick[(i+1)mod 5]);
		until false;




读者-写者问题


       我们可以允许多个Reader进程同时读一个文件,却不允许一个Writer进程和另一个Writer进程同时访问一个文件,也不允许一个Writer进程和另一个Reader进程同时访问一个文件,因为这会引起混乱。
       综上,“读者-写者”问题是保证一个 Writer 进程必须与其他进程互斥地访问共享对象的同步问题

1)记录型信号量解法:
      
      " 设置互斥信号量Wmutex,整形变量Readcount表示正在读的进程数目。只要有一个Reader进程在读,便不允许Writer进程去写。因此,仅当Readcount=0,表示尚无Reader进程在读时,Reader进程才需要执行Wait(Wmutex)操作。若Wait(Wmutex)操作成功,Reader进程便可去读,相应地,做Readcount + 1 操作。同理,仅当Reader进程在执行了 Readcount 减 1 操作后其值为0时,才须执行 signal(Wmutex)操作,以便让Writer进程写。又因为 Readcount是一个可被多个 Reader 进程访问的临界资源,因此,也应该为它设置一个互斥信号量rmutex。" 文献[1]

Var rmutex, wmutex: semaphore:=1,1;
	Readcount: integer:=0;
	begin
	parbegin
		Reader: begin
			repeat
				wait(rmutex);
				if readcount=0 then wait(wmutex);
					Readcount:=Readcount+1;
				signal(rmutex);
				...
				perform read operation;
				...
				wait(rmutex);
				readcount:=readcount-1;
				if readcount=0 then signal(wmutex);
				signal(rmutex);
			until false;
		end
		writer: begin
			repeat
				wait(wmutex);
				perform write operation;
				signal(wmutex);
			until false;
		end
	parend
end


2)信号量集解法:
      这里的读者写者问题与前面的稍有不同,增加了一个限制--最多只允许RN个Reader进程同时读共享对象。因此引入信号量L,初始值为RN." 文献[1]

Var RN integer;
	L, mx: semaphore:=RN,1;
	begin
		parbegin
			reader: begin
					repeat
						Swait(L,1,1);
						Swait(mx,1,0);
						...
						perform read operation;
						...
						Ssignal(L,1);
					until false;
				end
			writer: begin
					repeat
						Swait(mx,1,1; L,RN,0);
						perform write operation;
						Ssignal(mx,1);
					until false;
					end
				parend
			end


进程通信

       之前讲述的进程的互斥和同步中,对于信号量机制,要访问统一共享资源的进程都可以操作信号量,相当于用信号量进行“通信”;对于管程机制,要访问同一共享资源的进程可以先后进入管程,使用数据结构里的操作访问资源的字段值,这也是进程间的“通信”。
       然而,这些通信只能传递很少的数据,属于“低级通信”的范畴,下面要介绍的是“高级通信”--能传输大量的数据。主要的通信机制有三种:1)共享存储器 2)消息传递 3)管道通信,最后还会提到 消息缓冲队列的通信机制。

共享存储器

1)如果是共享数据结构的话,就和进程的互斥和同步中的管程无异,比较低效,只能传输少量数据。
2)如果是共享存储区的话,比较高效,能传输大量数据。

消息传递

传递格式化的message,按实现分为“直接通信”、“间接通信”

直接通信:

(发送进程)利用OS提供的命令,直接把消息发送给接受进程。
[1]中有一个例子,使用直接通信的原语(primitive)来解决生产者-消费者问题


间接通信:

       进程需要通信时,创建数据结构的一个实例(instance)--叫作 “信箱“,然后利用OS提供的原语对实例进行操作。不通信的时候,可以撤销此实例。信箱还分为:私有、公有、共享 三种,其中私有信箱的通信链路是单链路,公有和共享信箱的通信链路是双链路。

消息传递系统中的若干问题

1)通信链路

2)消息的格式

3)进程同步方式

      1. 发送进程阻塞,接收进程阻塞--“紧密同步”
      2. 发送进程不阻塞,接收进程阻塞--“消息来了才被唤醒”--应用最广
      3. 发送进程,接收进程均不阻塞--较常见


管道通信

pipe文件连接一个 Reader 进程和一个Writer进程,pipe作为管道可传送大量数据
前提:1、互斥  2、同步  3、确认对方是否存在。


消息缓冲队列

所涉数据结构:

1)消息缓冲区 
2)在PCB中添加相关字段: mq(消息队列队首指针)、mutex(消息队列互斥信号量)、sm(消息队列资源信号量)


线程


基本概念


引入原因


简单:
        进一步提高并发度,提升吞吐量

详细:
        进程的创建、撤销、切换的开销较大,在原来的系统中进程不仅是调度和分派的基本单位,也是拥有资源的基本单位。引入线程,让它成为调度和分配的基本单位 (进程仍是拥有资源的基本单位),可以减少开销(主要是进程切换--在同一进程中,线程的切换并不会引起进程的切换),提升多处理器性能。

线程与进程的不同

1)调度 2)并发性 3)拥有资源 4)系统开销

线程的属性

1)轻型实体 2)调度和分派的基本单位 3)可并发执行 4)共享进程资源(共享进程的地址空间)

线程的状态

1)状态参数 --寄存器状态、堆栈、线程运行状态、优先级、线程专有存储器、信号屏蔽
2)线程运行状态--执行态、就绪态、阻塞态

线程的创建和终止


多线程OS中进程的特点

1)作为系统资源分配的单位 2)可包括多个线程 3)进程不是一个可执行的实体,其中的线程才是

线程间的同步和通信

1. 互斥锁(mutex)类似于进程同步中的互斥信号量
2. 条件变量
3. 信号量机制
                          1)私有信号量-用于一个进程内的线程同步,OS不可见 
                          2)公有信号量-用于不同进程或不同进程中的线程的同步,OS可见。又称系统信号量

线程的种类

1. 内核支持线程(KST:kernel supported threads)
2. 用户级线程(ULT:user level threads)

1. 内核支持线程

关键:

内核在内核空间为每一个内核支持线程设置一个线程控制块,内核通过这个来调控它们


优点:

1)在多处理器系统中,同一进程中的内核支持线程可以并行执行(由内核调度)。

2)若进程中的一个线程被阻塞了,内核可以调度进程中的其他线程占用CPU来运行,也可运行其他进程中的线程。

3)此种线程具有很小的数据结构和堆栈,线程间的切换迅速,开销小。

4)内核本身也可以采用多线程技术,提高系统的执行速度和效率。


缺点:

对用户的线程切换来说,因为用户的线程运行在用户态,切换时需要从用户态转到内核态进行,开销大。(纯内核支持线程的系统,其线程调度和管理是在内核实现的。)


2. 用户级线程

关键:
此种线程仅存在于用户空间中,内核不可见

优点:
1)线程切换不需转到内核态(同个进程中的用户级线程切换开销极小)
2)可专门为进程定制调度算法(用于管理一个进程中的线程)
3)用户级线程的实现与OS平台无关

缺点:
由于用户级线程对内核是不可见的,因此对于内核来说,它只看到其进程粒度,因此会有以下两种缺点:
1)当一个用户级线程被阻塞的时候,整个进程都被阻塞
2)用户级线程不能利用多处理器的优点,来实现多线程并行执行,因为在内核看来,这就是一个进程而已。



线程的实现

1. 内核支持线程的实现

Key

     系统在创建一个新进程的时候,为它分配一个任务数据去PTDA(Per Task Data Area),含若干线程控制块(TCB)空间。每一个TCB可保存线程标识符、优先级、线程运行的CPU状态。虽然这些信息与用户级线程TCB的信息相同,但却是保存在内核空间中的。

     内核支持线程的创建、撤销与进程的相似。有的实现中撤销一个线程并不立即回收其资源和TCB。以后要再创建一个新线程时,可以直接利用已被撤销但仍然葆有资源、TCB的线程作为新线程。


2. 用户级线程的实现

Key
     用户级线程在用户空间实现,需要运行在一个中间系统上面。因此有两种实现方式。

1)运行时系统(Runtime System)
运行时系统--就是一堆线程管理的函数,作为用户级线程和内核之间的接口。用户级线程之间的切换无需经过内核态,速度很快。需要系统调用的时候,只管和运行时系统沟通,后者和内核沟通。


2)内核控制线程
又称“轻型进程”(LWP)。和上面类似,LWP相当于用户级线程和内核之间的中间人,用户级线程利用LWP才能和内核通信,可以让多个用户级线程连接到LWP上实现“多路复用” (个人认为只是简单的分时复用),但每次只能有一个用户级线程利用这个LWP和内核沟通。

用户级线程和内核控制线程的连接:

1)一对一
       为每一个用户级线程都有一个内核控制线程与之连接,当一个线程阻塞时,可以调度另一个线程与LWP连接运行。在多处理器系统中,则有多个线程并行执行,并行能力强。由于每个用户级线程都有对应创建一个内核控制线程,开销较大


2)多对一
       多个用户级线程映射到一个内核控制线程,这些共用一个内核控制线程的用户级线程一般属于一个进程,线程管理的开销小(少分配了很多LWP)。但是由于一个进程只对应一个LWP,其内部同时也只能有一个线程通过LWP访问内核,当一个线程在访问内核时阻塞,整个进程都会阻塞。在多处理器系统中,一个进程的多个线程无法实现并行。在下图中,颜色相同的属于同一个进程。


3)多对多
       此模型综合以上两种模型的优点,将多个用户线程映射到多个内核控制线程,内核控制线程的数目少于等于用户线程的数目。

       由以上可知,用户级线程中的内核控制线程的多对一模型,在多处理器下,是不能实现线程并行的。运行时系统则不知。


References:

[1]  计算机操作系统(第三版)汤小丹 梁红兵 哲凤屏 汤子瀛 编著

[2]  操作系统--精髓与设计原理(第七版)William Stallings  著;陈向群 陈渝  译

1.目的: 自行编制模拟程序,通过形象化的状态显示,深入理解进程概念进程之间的状态转换及其所带来的PCB内容 、组织的变化,理解进程与其PCB间的一一对应关系。 2. 内容及要求: 1) 设计并实现一个模拟进程状态转换及其相应PCB内容、组织结构变化的程序。 2) 独立编写、调试程序。进程的数目、进程的状态模型(三状态、五状态、七状态或其它)以及PCB的组织形式可自行选择。 3) 合理设计与进程PCB相对应的数据结构。PCB的内容要涵盖进程的基本信息、控制信息、资源需求及现场信息。 4) 设计出可视性较好的界面,应能反映出进程状态的变化引起的对应PCB内容、组织结构的变化。 5) 代码书写要规范,要适当地加入注释。 6) 认真进行预习,完成预习报告。 7) 实验完成后,要认真总结,完成实验报告。 3.使用的数据结构及说明: 在本实验中,主要用到的数据结构是PCB的结构,其中PCB的数据结构如下: struct PCB { int P_Id; //PCB的ID号 char P_Name[10]; //PCB的名称 char P_State[10]; //PCB状态 int P_Runtime; //PCB的所需要的运行时间 int P_Requiry; //PCB所需要的资源要求 struct PCB * next ; //PCB块的下一个指针 } ; 其中,P_Id,和P_Name用来标示一个进程,而P_State用来标示进程的五种状态:Create_state,Ready_state,Block_state,Run_state,Exit_state。P_Runtime标示要完成一个进程所需要的时间。P_Requiry标示一个进程的执行所需要的其他条件,当其他的条件满足,则P_Requiry置1,否则置0。Struct PCB * next 用来指向同一队列中的下一个PCB块。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值