第二章 进程通信(五)
2.6 进程通信
2.6.1 进程通信的类型
进程通信是进程之间的信息交换,由于进程的互斥与同步,需要在进程间交换一定的信息,只能把它们称为低级进程通信。高级通信工具能够高效的传送大量数据
1. 共享存储系统
在共享存储器中,相互通信的进程共享某些数据结构或共享,进程之间能够通过这些空间进行通信。
又可把它们分为两种类型:
- 基于共享数据结构的通信方式
- 基于共享存储区的通信方式(例如手机中的复制粘贴)
2. 管道(pipe)通信
-
所谓“管道”,是用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,又名 pipe 文件
- 向管道(共享文件)提供输入的发送进程(写进程)以字符流形式将大量数据送入管道中。
- 接受管道输出的接收进程(读进程)则从管道中接受(读)数据
- pipe 文件存在内存中
-
为了协调双方的通信,管道机制必须提供一下三个方面的协调能力
- 互斥:一个进程在操作,另一个进程就等待
- 同步:当写进程把一定的数据写入pipe(共享文件),便睡眠等待,直到读进程取走数据后再把它唤醒。当读进程读一个空 pipe 时,也应该睡眠等待,直到写进程写入管道后才将之唤醒。
- 确定对方是否存在,只有确定对方已经存在才能进行通信
3. 消息传递系统
该机制,进程不必借助任何共享存储区或数据结构,而是以格式化的信息为单位,将通信的数据封装在消息中,并利用操作系统提供一组通信命令(原语),在进程之间进行消息传递,完成进程间的数据交换。
实现方式分成两类
- 直接通信方式
- 间接通信方式
4.客户机-服务器系统
(1)套接字(Socket)= IP+端口号
- 网络通信接口
- 被设计用在一个主机上多个用用程序之间的通信(即进程间的通信)
- 主要解决多对进程同时通信时端口和物理线路的多路复用问题
(2)远程过程调用和远程方法调用(408看看了解就得了,自主命题emmm看题吧)
远程过程(函数)调用 RPC:一个通信协议,用于通过网络连接的系统。该协议允许于一台主机(本地)系统上的进程调用另一台主机(远程)系统上的进程,而对程序员表现为常规的过程调用,无需额外的为此编程。
远程调用的主要步骤:(自主命题:客户存根、服务器存根)
2.6.2 消息传递通信的实现方式
1. 直接消息传递系统
在直接消息传递系统中采用直接通信方式,即发送进程利用 OS 所提供的发送命令(原语),直接把消息发送给目标进程。
- 直接通信原语
- 对称寻址方式(1对1)
- 非对称寻址方式(1对多)
- 消息格式
- 所传递的消息,必须具有一定的消息格式
- 单机环境中,由于发送和接收进程处于同一机器中,有着相同环境,所以消息格式简单,可采用比较短的定长消息格式,以减少对消息的处理和存储开销。
- 可采用变长消息格式,即进程所发送消息的长度是可变的,对于变长消息,系统无论再处理方面还是存储方面,都可能付出更多的开销,有点在于方便用户。
- 进程的同步方式:不论是发生进程还是接收进程,在完成消息的发送或接收后,都存在两种可能性,即进程或者继续发送(或接收)或者堵塞
- 通信链路:发送进程和接收进程之间够进行通信,必须在两者之间建立一条通信链路
- 第一种建立方式:由发送进程在通信之前用显式的“建立连接”命令(原语),请求系统为之建立一条通信链路,在链路使用完后拆除链路。
- 第二种建立方式:发送进程无需明确提出建立链路请求,只需利用系统提供的发送命令(原语),系统会自动为之建立一条链路
- 用于单机系统中
根据通信方式的不同,又把链路分成两种:
- 用于单机系统中
- 单向通信链路(单工):只允许进程向接收进程发送消息,或者相反。
- 双向链路(全双工):即允许由进程 A 向进程 B 发送消息,也允许进程 B 同时向进程 A 发送消息。
2. 信箱通信(间接消息传递系统)
(1)信箱的结构:信箱定义位一种数据结构
逻辑上分成两部分(这与生活中互发邮件的功能很像)
- 信箱头
- 信箱体
(2)信箱的原语(系统为邮箱通信提供了若干条原语) - 邮箱的创建和撤销
- 消息的发送和接收
(3)信箱的类型(稍微注意有考点)
根据邮箱创建者不同,分成以下三类 - 私用邮箱
- 公用邮箱(OS创建进行指派)
- 共享邮箱
2.6.3 直接消息传递系统的实例
消息缓冲队列通信机制(广泛用于本地进程):发送进程利用 Send 原语将消息直接发送给接收进程,接收进程则利用 Receive 原语接收消息。
1. 消息缓冲队列通信机制中的数据结构
(1)消息缓冲区:sender、size、text、next
(2)PCB 中有关通信的数据项
- mq 消息队列指针
- mutex 互斥信号量
- sm 资源信号量
A写者,B读者
//自主命题看看
//进程A:
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 , receuver.j); //获得接收进程内部标识符(pid是进程的唯一标识)
wait(j.mutex);
insert(j.mq,i); // 将消息缓冲区插入消息队列;
signal(j.mutex);
signal(j.sm);
//进程B:
j:=internal name; //j 为接收进程内部的标识符
wait(j.sm);
wait(j.mutex);
remove(j.mq,i); //将消息队列中第一个消息出;
signal(j.mutex);
b.sender:=i.sender; //将消息缓冲区 i 中的信息复制到接收区 b;
b.size:=i.size;
b.text:=i.text;
2.7 线程的基本概念
线程的目的:减少程序在并发执行时所付出的时空开销,使OS具有更好的并发性
1. 还记得进程的两个基本属性吗?
- 进程是一个可拥有资源的独立单位
- 进程又是一个可独立调度和分派的基本单位,每个进程在系统中有唯一的 PCB (用于进程的切换)
2. 进程 ———— 程序并发执行所需付出的时空开销
- 创建进程
- 撤销进程:对所占有的资源执行回收操作,然后再撤销 PCB
- 进程切换:对进程进行上下文切换时,需要保留当前进程的 CPU 环境,设置新选中进程的 CPU 环境,因而需要花费不少的处理机时间
3. 线程 ————>== 作为调度和分派的基本单位==
设法将进程的两个属性分开,由 OS 分开处理,既不把作为调度和分派的基本单位,也同时作为拥有资源的单位
2.7.1 线程进程的比较
- 调度的基本单位进程内,切换代价低
同一进程中,线程的切换不会引起进程的切换,但从一个进程中的线程切换到另一个进程中的线程时,将引起进程切换
- 并发性
在一个进程中的多个线程之间亦可以并发执行,使得操作系统具有更好的并发性
- 拥有资源
- 线程自己不拥有资源(也有一点必不可少的资源),但它可以访问其隶属进程的资源,即一个进程的代码端、数据及所拥有的系统资源
- 线程控制块 TCB
- 相对进程而言,独立性低
- 系统开销
- 进程切换代价远高于线程
- 由于一个线程和的多个线程具有相同的地址空间,在同步和通信的实现方面线程也比进程容易。
- 支持多处理器系统(多线程多处理器)
2.7.3 线程的状态和线程控制块
1. 线程运行的三个状态
- 执行状态:线程获得处理机而正在运行
- 就绪状态:线程具备了各种执行条件,只需要再获得 CPU 便可立即执行
- 阻塞状态:线程在执行中因某事受阻而处于暂停状态。例:当一个线程执行从键盘读入数据的系统调用时,该线程被阻塞。
2. 线程控制块 TCB
用于控制和管理线程的信息记录再贤臣控制块中
- 线程标识符
- 寄存器状态,包括程序计数器 PC和堆栈指针中的内容;堆栈,在堆栈中通常保存有局部变量和返回地址。
- 线程运行状态,用于描述线程正处于何种运行状态
- 优先级,描述线程执行的优先程度
- 线程专有存储器,用于保存线程自己的局部变量拷贝;
- 信号屏蔽,即对某些信号加以屏蔽
3. 多线程OS中的进程属性
OS 支持在一个进程中的多个线程能并发执行,但此时的进程不再作为一个执行的实体,多线程 OS 中的进程有以下属性:
- 进程是一个可拥有资源的基本单位。
- 多线程可以并发执行
- 进程已不是可执行的实体
2.8 线程的实现(重点)
2.8.1 线程的实现方式
- 用户级线程
- 内核支持线程
- 同时实现上述两种类型的线程
1. 内核支持线程(与平台有关)
在操作系统的内核支持下运行的,创建、阻塞、撤销和切换等,也是在内核空间实现的,内核根据该控制块而感知某县城的存在,并对其加以控制。
内核支持线程实现方式主要有 4 个优点(自主命题通杀,很重要)
- 在处理器系统中,内核能够同时调度同一线程中的多个线程并行执行;
- 如果进程中的一个线程被阻塞,内核可以调度该线程中的其他线程,来占有处理器运行;也可以运行其他进程中的线程
- 内核支持线程具有很小的数据结构和堆栈,线程的切换比较快,切换开销小。
- 内核本身也可以采用多线程技术,可以提高系统的执行速率和效率
2. 用户级线程
用户级线程是在用户空间中实现的,用户级线程与内核无关,用户级线程的任务控制块都是设置在用户空间,而线程所执行的操作也无需内核帮助,因而内核完全不知道用户级线程的存在。
- 使用用户级线程方式有许多优点:
- 线程切换不需要转换到内核空间
- 调度算法可以是进程专用的
- 用户级线程的实现与 OS 平台无关,因为对于线程管理的代码是属于用户程序的一部分,所有的应用程序都可以对之进行共享
- 用户级线程方式的主要缺点:(很重要)
- 系统调用的阻塞问题:一个线程被阻塞,那么该进程就被阻塞(与内核可以形成对比)
- 多线程应用不能利用多处理进行多重处理的优点,内核每次分配给一个进程的仅有一个 CPU,因此进程中只能有一个线程执行。(与内核级还形成对比)
3. 组合方式
内核支持当多个内核支持线程的创立、调度和管理,同时也允许用户应用程序建立、调度和管理用户级线程。
- 多对一:发挥不出内核级特点,不能解决系统调用的阻塞问题
- 一对一,多对多:多个 CPU 并行执行
2.8.2 线程的实现
1. 内核支持线程的实现
在仅设置内黑支持线程的 OS 中,一种可能的线程控制方式是:系统在创建一个新进程时,便为它分配一个任务数据区 PTDA,其中包括若干个线程控制块 TCB 空间=。
2. 用户级线程的实现
- 运行时系统
- 实质上是用于管理和控制线程的函数(过程)的集合,其中包括创建和撤销线程的函数、线程同步和通信的函数,以及实现线程调度的函数等(正是因为这些函数,用户级线程才与内核无关)
- 运行时系统中的所有函数都驻留在用户空间,并作为用户级线程与内核之间的接口
- 内核控制线程
- 又称为轻型进程 LWP
- 每一个进程都拥有多个 LWP,同用户级线程一样,每个 LWP 都有自己的数据结构(TCB),其中包括线程标识符、优先级、状态,另外还有栈和局部存储区等。LWP 也可以共享进程所拥有的资源。
- **LWP 可以通过系统调用来获得内核提供的服务,当一个用户级线程运行时,只需将它连接到一个 LWP 上
- 这种线程实现方式就是组合方式
2.8.3 线程的创建和终止
本质就是 TCB 块的创建和释放