第二章 进程管理(4)

管程机制

1.管程的组成
名为monitor_name的管程

Type monitor_name= monitor
    variable declarations;
    procedure entry P1(){…}
    procedure entry P2(){…}
    procedure entry Pn(){…}
    initialization code;

2.管程的特点
任何进程只能通过调用管程提供的过程入口才能进入管程访问共享数据
就如同使用临界资源,就要先通过其信号量的申请。
任何时刻,仅允许一个进程在管程中执行某个内部过程
管程如何实现同步
对共享变量互斥操作
管程的特点直接实现了该要求,进程一次一个进入管程调用内部过程操作共享变量。
管程的互斥访问完全由编译程序在编译时自动添上,无须程序员关心,能保证正确。
操作的同步控制
靠条件变量的操作管理实现。
进入管程但不能获取资源操作的过程将阻塞,并在满足条件时被唤醒执行。

type p_c=monitor
    var in,out,count: interger;
           buffer: array[0,…,n-1] of item
           x,y: condition;
procedure entry put(var product:item)
{  if count>=n then x.wait;
    buffer[in]=product;
    in=in+1 mod n;
    count=count+1;
    y.signal;   }
procedure entry get(var product:item)
{  if count<=0 then y.wait;
    nextc=buffer[out];
    out=out-1 mod n;
    count=count-1;
    x.signal;	}
{	in=out=0;
	count=0;		}

生产者-消费者问题的管程解决方法

Producer:
begin
   repeat
  生产an item in nextp;
   p_c.put(nextp);
   until
end

consumer:
begin
   repeat
   p_c.get(nextc);
   消费an item in nextc;
   until
end

3.条件变量
局部于管程的变量有两种:
普通变量
条件变量(用于控制进程阻塞和唤醒)
类似信号量变量,但不取具体值;相当于每个阻塞队列的队列指针。
对条件变量的操作需结合对普通变量的条件判断,从而控制进程状态。
4.管程的优点
保证进程互斥地访问共享变量,并方便地阻塞和唤醒进程。
管程可以以函数库的形式实现。相比之下,管程比信号量好控制。
管程可增强模块的独立性
系统按资源管理的观点分解成若干模块,用数据表示抽象系统资源,使同步操作相对集中,从而增加了模块的相对独立性
引入管程可提高代码的可读性,便于修改和维护,正确性易于保证
采用集中式同步机制。一个操作系统或并发程序由若干个这样的模块所构成,一个模块通常较短,模块之间关系清晰。
5.管程的缺点
大多数常用的编程语言中没有实现管程,如果某种语言本身不支持管程,那么加入管程是很困难的。
虽然大多数编程语言也没有实现信号量,但可将P、V操作作为一个独立的子例程或操作系统的管理程序调用加入。

进程通信

进程通信是指进程之间的信息交换
一、低级通信——进程之间的互斥和同步
信号量机制是有效的同步工具,但作为通信工具缺点如下:
(1)效率低(通信量少)
(2)通信对用户不透明(程序员实现,操作系统只提供共享存储器供代码操作)

二、高级进程通信
用户直接利用操作系统提供的一组通信命令,高效地传送大量数据的通信方式。
操作系统隐藏了进程通信的细节,对用户透明,减少了通信程序编制上的复杂性。

1.进程通信的类型

①共享存储器系统(操作存储区方式)

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

a.基于共享数据结构的通信方式(低级)

程序员:提供对公用数据结构的设置及对进程间同步的处理。
操作系统:提供共享存储器。
特点:复杂、低效率,还只适合传递相对少量的数据。

b.基于共享存储区的通信方式(高级)

在存储器中划出了一块共享存储区,诸进程可通过对共享存储区中数据的读或写来实现通信。
进程通信前先向系统申请获得共享存储区中的一个分区,并指定该分区的关键字;
若系统已经分给了其他进程,则将该分区的描述符返回给申请者,申请者把获得的共享存储分区连接到本进程上;此后,便可像读、写普通存储器一样地读、写该公用存储分区。多进程借助该区通信。

②消息传递系统

最广泛使用的一种,进程间的数据交换,以格式化的消息为单位。屏蔽底层复杂操作。
单机:操作系统底层编程中的消息传递系统调用;
计算机网络:消息称为报文。程序员直接利用系统提供的一组通信命令(原语)进行通信。(④客户机-服务器系统)

③管道通信

所谓“管道”,是指用于连接一读进程和一写进程以实现通信的一个共享文件,又名pipe文件。
向共享文件输入的写进程以字符流形式将大量的数据送入管道;而接收管道输出的读进程则从管道中接收(读)数据。

④Client-Server system

套接字(Socket)
远程过程调用(远程方法调用)
RPC应用开发步骤

1>定义客户端、服务器端的通信协议(定义服务过程的名称、调用参数的数据类型、返回参数的数据类型、底层传输类型(UDP/TCP)等。
2>开发客户端程序。
3>开发服务器端程序。

2.消息传递通信的实现方法

1)直接通信方式

发送进程利用OS所提供的发送命令(原语),直接把消息发送给目标进程。此时,发送进程和接收进程都以显式方式提供对方的标识符。通常利用系统通信命令(原语):

Send(Receiver, message);
Receive(Sender, message);

利用直接通信原语解决生产者——消费者问题

Producer:
repeat
           …
           produce an item in nextp;
           …
           send(consumer, nextp);
until  false;
Consumer:
repeat
           receive(producer, nextc);
           …
           consume the item in nextc;
until  false;
2)间接通信方式

基于共享数据结构的实体用来暂存发送给目标进程的消息;接收进程则从该实体中,取出对方发送给自己的消息。通常把这种实体称为信箱。
消息在信箱中可以安全地保存,只允许核准的目标用户随时读取。既可实时通信,又可非实时通信。
在这里插入图片描述
2)信箱消息的发送和接收
进程之间利用信箱进行通信时,必须使用共享信箱。

  Send(mailbox, message);
    Receive(mailbox, message);

3.消息传递系统的实现

单机和网络环境下的高级进程通信广泛采用“消息传递”方式,需要考虑的问题:

①通信链路的建立

计算机网络环境下,用原语显式建立/拆除链路
单机系统只须利用系统原语,进程间链路由系统自动管理。

②消息格式

单机系统,发送与接收进程在同一台机器,环境相同故格式简单;
网络环境下,受不同目标机器的环境和长距离信息传输等因素的影响,消息格式较复杂,消息常是“大头+正文”

③同步方式

发送进程阻塞、接收进程阻塞(无缓冲紧密同步)
发送进程不阻塞、接收进程阻塞(服务器程序)
发送进程和接收进程均不阻塞(缓冲队列)

4.消息缓冲队列通信机制

①不需管理链路
②定义简单数据结构(亦即消息格式)
③实现发送和接收的操作原语

数据结构

本机通信消息结构简单,如下:

type message buffer = record
		sender;   发送者进程标识符
		size;   消息长度
		text;   消息正文
		next;   指向下一消息缓冲区的指针
end
PCB中需要记录有关通信的信息项
type ProcessControlBlock =record
	 …
	 mq;         消息队列队首指针
	 mutex;    消息队列互斥信号量
	 sm;          消息队列资源信号量
	 …
end
原语代码:

发送原语:

procedure send(receiver, a)
    begin
        getbuf(a.size, i);  根据a.size申请缓冲区
        i.sender :=a.sender;  将发送区a中的信息复制到 i
        i.size :=a.size; 
        i.text :=a.text; 
        i.next :=0;

获取接收进程内部标识符:

   getid(PCB set, receiver, j); 
	  wait(j.mutex);
	   insert(j.mq, i); 将消息缓冲区插入目标消息队列
	   signal(j.mutex);
	   signal(j.sm);
          end

接收原语:

procedure receive(b)
    begin
        j:=internal name;  j为接收进程内部标识符
       wait(j.sm);
       wait(j.mutex);
	 remove(j.mq, i);  将消息队列中的第i个消息移出
        signal(j.mutex);
        b.sender :=i.sender;
        b.size :=i.size;  将消息缓冲区i中的信息
        b.text :=i.text;  复制到接收区b
        end

线程

1.线程的引入

多道程序管理:追求效率的目的下实现“并发”
多线程系统中,同一个进程中的多个线程
共享进程资源
可并发执行

2.线程的属性

轻型实体:只需一点必不可少的、能保证独立运行的资源。(TCB)
独立调度和分派的基本单位:调度切换迅速且开销小。
可并发执行
共享进程资源:同进程中的线程可共享相同的进程地址空间、已打开文件、信号量机构等。

3.线程的信息

状态参数
标识符、运行状态、优先级、寄存器状态、堆栈、专有存储器、信号屏蔽等。
运行状态
执行、就绪、阻塞

4.线程的创建和终止

创建新线程
利用线程创建函数(或系统调用),提供相应参数。线程创建函数执行完后,返回一个线程标识符供以后使用。
线程被终止
不立即释放资源,只有当进程中的其它线程执行分离函数后,资源才分离出来能被其它线程利用。
被终止而未释放资源的线程仍可被需要它的线程调用,使其重新恢复运行。

多线程变成举例
netgameserver.java
public class netgameserver	//主类
{  static int usercount=1;
	public static void main(String args[])//main函数
  	{Socket client=null;	...
	  new Serthread(client).start();}//启动新线程 …}
}
class Serthread extends Thread		//自定义的线程类
{ 	String url="jdbc:odbc:userInfo";	
  	Connection con;  Statement stmt;
	Socket thclient;
	DataInputStream in=null;
	…
	public void run()//线程执行run函数----->
    {System.out.println("a server thread started !");
      boolean userlistfirshow=false;
      while(true)//开始监听
	  {	  	
	  	if(!userlistfirshow)
		……}
	}
}

5.多线程系统中的进程

进程只是用于分配系统资源
包括多个线程
不是执行实体,线程在进程范围内作为执行实体。

线程与进程的比较

调度:线程作为CPU调度的基本单位,而进程只作为其它资源分配单位。
并发性:进程之间可以并发,实质上是不同进程中的两个线程并发。一个进程的多个线程之间亦可并发。
拥有资源:进程间资源相互独立;同一进程的各线程间共享。某进程内的线程在其它进程不可见
系统开销:线程上下文切换在同进程环境下上下文切换要快得多。因为同进程内线程间共享内存地址和打开的文件资源;

6.线程的管理

同步和通信机制
(1)互斥锁
比较简单的,控制线程互斥访问资源;
适用于高频度使用的关键共享数据和程序段;
unlock和lock两个锁操作原语;
(2)条件变量
与互斥锁一起使用
锁保证互斥进入临界区,但利用条件变量使线程阻塞

不满足条件时,wait条件变量:
释放互斥锁
进程阻塞在条件变量指向队列中
被唤醒后要重新再设互斥锁
(3)信号量
私用信号量(private samephore)
用于同进程的线程间同步,数据结构存放在应用程序的地址空间。属于特定进程,OS感知不到其存在。
公用信号量(public samephore)
用于不同进程间或不同进程中线程的同步,数据结构由OS管理,存放在受保护的系统存储区。

7.线程的实现方式

(1)内核线程KST
依赖于内核,利用系统调用由OS内核在内核空间完成创建、撤消、切换等线程工作。

优缺点:

优点:
1>多处理器系统下可实现多线程并行
2>一个线程发起系统调用而阻塞,不会影响其它线程的运行
3>线程切换开销远小于进程切换
4>内核本身也采用多线程技术可提高系统执行速度和效率
缺点:
用户态运行线程,调度和管理线程则是内核态。模式的切换开销大。
(2)用户线程ULT
调度由应用软件内部进行,通常采用非抢先式和更简单的规则,也无需用户态/核心态切换,速度比kst快。

优缺点:

优点:
1>用户线程的维护由应用进程完成;内核不了解用户线程的存在;线程切换不需要内核特权;
2>用户线程调度算法可针对应用优化;
3>多线程的实现与平台无关
缺点:
1>一旦系统调用引起进程阻塞,则整个进程的所有线程都不能执行
2>以进程为单位分配cpu,所有在多处理器系统中没有优势
(3)组合方式
内核支持多KST线程的管理,同时也允许用户应用程序级的线程管理。

猜你喜欢

转载自blog.csdn.net/weixin_42630417/article/details/84377914