网站引导页模板,阿里云注销网站,取消网站的通知,建筑工程项目简介使用多进程协作来实现应用和系统是一种被广泛使用的开发方法。多进程协作主要有以下三点优势。将功能模块化#xff0c;避免重复造轮子。增强模块间的隔离#xff0c;提供更强的安全保障。提高应用的容错能力。进程间通信#xff08;Inter-Process Communication#xff0c… 使用多进程协作来实现应用和系统是一种被广泛使用的开发方法。多进程协作主要有以下三点优势。将功能模块化避免重复造轮子。增强模块间的隔离提供更强的安全保障。提高应用的容错能力。进程间通信Inter-Process CommunicationIPC则是多进程协作的基础。一般而言IPC至少需要两方如两个进程参与。根据信息流动的方向这两方通常被称为发送者和接收者。在实际使用中IPC经常被用于服务调用因此参与IPC的两方又被称为调用者和被调用者或者客户端和服务端。图7-1是一个简单的IPC设计。它假设内核已为两个进程映射了一段共享内存且共享内存刚好可以存放两个消息发送者消息和接受者消息。 01 进程间通信的重要功能数据传递消息传递message passing是IPC中常用的数据传递方式即将数据抽象成一个个的消息进行传递。不同的IPC设计有不同的消息抽象且消息传递往往需要一个“中间人”如共享内存。控制流转移当一个通信发生时内核将控制流从发送者进程切换到接收者进程返回的过程类似。IPC中的控制流转移通常是利用内核对进程的运行状态和运行时间的控制来实现的。 02 进程间通信的分类单向IPC、双向IPC、单/双向IPC单向IPC通常指消息在一个连接上只能从一端发送到另一端双向IPC则允许双方互相发送消息。而单/双向IPC则会根据通信中具体的配置选项等来判断是否需要支持单向或双向的通信。实际中很多系统选择的是单/双向IPC这样可以比较好地支持各种场景。当然如管道、信号等只支持单向IPC的机制在实际中同样有较多的应用。同步IPC和异步IPC简单来看同步IPC指它的IPC操作如Send会阻塞进程直到该操作完成而异步IPC则通常是非阻塞的进程只要发起一次操作即可返回而不需要等待其完成。相比异步而言同步IPC有着更好的编程抽象。然而同步IPC在操作系统的发展中逐渐表现出一些不足。一个典型的问题是并发。总的来看目前大部分操作系统内核都会选择同时实现同步和异步IPC以满足不同的应用需求。 03 进程间通信的相关机制超时机制超时机制扩展了IPC通信双方的接口允许发送者/接收者指定它们发送/接收请求的等待时间。比如一个应用程序可以花费5秒等待文件系统进程的IPC请求处理操作。如果超过5秒仍然没有反馈则由操作系统内核结束这次IPC调用返回一个超时的错误。通信连接管理对于基于共享内存的进程间通信方案通信连接的建立通常是在建立共享区域的一瞬间完成的而对于涉及内核的控制流转移的通信而言通信连接管理是内核IPC模块的很重要的一部分。虽然实际的系统中会有各种不同的实现但是它们大部分可以被归为两类——直接通信和间接通信。直接通信是指通信的进程一方需要显式地标识另一方。间接通信需要经过一个中间的信箱来完成通信每个信箱有自己唯一的标识符而进程间通过共享一个信箱来交换消息。权限检查进程间通信通常依赖于一套权限检查的机制来保证连接的安全性。例如seL4等微内核系统中的Capability机制会将所有的通信连接抽象成一个个的内核对象。而每个进程对内核对象的访问权限以及能够在该内核对象上执行的操作由Capability来刻画。当一个进程企图和某其他进程通信时内核会检查该进程是否拥有一个Capability是否有足够的权限访问一个连接对象并且对象是指向目标进程的。类似地宏内核如Linux系统通常会复用其有效用户/有效组的文件权限以刻画进程对于某个连接的权限。命名服务命名服务像是一个全局的看板可以协调服务端进程和客户端进程之间的信息。简单来说服务端进程可以将自己提供的服务告诉命名服务进程比如文件系统进程可以注册一个“文件系统服务”网络系统进程可以注册一个“网络服务”。而客户端进程可以去命名服务上查询当前的服务并选择自己希望建立连接的服务去尝试获取权限。具体是否分发权限给对应的客户端进程是由命名服务和对应的服务端进程根据特定的策略来判断的。 04 宏内核进程间通信宏内核下的典型的进程间通信机制具体包括管道System V中的消息队列、信号量、共享内存Linux信号机制以及套接字机制socket。宏内核操作系统中进程间通信更多的是应用之间的交互因此设计的重心通常会放在接口的易用性、稳定性等方面。图7-5给出了典型的宏内核进程间通信机制的对比。可以看到虽然在IPC的几个设计角度上几个方案都各有异同但是它们之间的主要区别是在数据抽象上。在实际的应用中虽然多种IPC方案都可以作为通信的选择但是应用程序往往会根据对数据抽象的需求来选择具体的方案。 05 微内核进程间通信由于进程间通信对于微内核系统性能的重要意义大部分微内核操作系统都会优先从性能角度来设计和实现进程间通信。Mach早期的微内核进程间通信设计Mach通过两种基本的抽象——端口port和消息message设计和实现了一种间接通信IPC通信的双方不需要显式指定另一方而是通过端口进行通信对应于“信箱”。进程之间通过端口流通的数据就是消息。作为一个早期的微内核系统Mach系统的性能比起当时的宏内核系统如UNIX还是存在不小的差距。其中一个原因是Mach为了实现大量的目标如可裁剪性、可移植性等导致其内核复杂且代码量较大。不过Mach的IPC设计仍对后来的很多系统有着非常重大的影响。Mach中端口和消息的设计使得进程间的通信和具体的进程是隔离开的。只要一个进程拥有某个端口其就能够通过这个端口和“另一端”的进程进行通信。后续的微内核系统设计大都考虑了Mach的思想不管是借鉴其设计还是将其缺陷引以为戒。 L4围绕进程间通信优化而设计的微内核系统根据Mach的经验Liedtke等研究人员开始研发L4系列的微内核系统。L4系列微内核系统的一个突出思路是进程间通信是微内核的核心功能需要围绕通信去完成整个系统的设计和实现。L4是当下仍然十分主流的微内核系统特别是后续衍生出了各种变体和相关的系统。在L4微内核中内核只保留了基本的功能包括地址空间、线程、进程间通信等并且不考虑如兼容性等要求而是选择针对特定硬件做极致的性能优化。这样做的好处就是内核的代码量非常少可以把少量的功能尽可能支持好。 LRPC迁移线程模型迁移线程thread migration是一个比较“极端”的优化性能的IPC设计。截止到目前我们了解到优化IPC性能的大部分工作会关注两个部分优化控制流切换的性能和优化数据传输的性能。迁移线程认为其他的IPC设计可以看成将需要处理的数据发送到另一个进程并让其处理。这也是为什么控制流切换和数据传输会成为主要的瓶颈。如果换一个角度将另一个进程处理数据的代码拉到当前进程那么我们是不是可以避免控制流的切换仍然是当前进程处理以及数据传输数据已经准备在当前进程中呢迁移线程就是围绕这个新的视角进行设计的。迁移线程方案被用在LRPC、Mach优化版本等系统中是目前纯软件进程间通信优化中效果最好的设计之一。迁移线程的基本原则是①简化控制流切换让客户端线程执行“服务端的代码”②简化数据传输共享参数栈和寄存器③简化接口减少序列化等开销④优化并发避免共享的全局数据结构。其中前两点原则都基于“将代码拉到本地”这个新的视角。迁移线程IPC和主流IPC设计的对比如图7-13所示。要做到“将代码拉到本地”迁移线程首先需要对线程结构进行解耦明确线程中哪些部分是对通信请求处理起关键作用的。然后这部分允许被调用者负责处理请求的逻辑运行在调用者的上下文中将跨进程调用变成更接近函数调用的形式。 如果使用迁移线程模型在进程间通信过程中内核不会阻塞调用者线程但是会让调用者线程执行被调用者的代码。整个过程没有被调用者线程被唤醒相反被调用者端更像是一个“代码提供者”。此外内核不会进行完整的上下文切换而是只切换地址空间页表等和请求处理相关的系统状态。其中不会涉及线程和优先级的切换也不会调用调度器。迁移线程的优点在于减少了内核调度的时间并简化了内核中的IPC处理。在多核场景下迁移线程方案还可以避免跨核通信引入的开销。 06 案例分析Android Binder在Android场景下进程间通信在大部分情况下做的其实是“远程过程调用”。服务端进程负责提供具体的服务客户端进程则通过进程间通信来发起服务请求并获得服务端进程处理后的结果。除了通信双方进程外在Binder IPC中还引入了一个Context Manager进程。Context Manager提供命名服务它的任务是建立通信连接。在Binder IPC的内核设计中提供了句柄handle的抽象来表示IPC对象即一个通信连接。句柄和我们熟悉的文件描述符其实很相似用户通过对句柄的操作来发起对特定进程的通信。和之前的进程间通信设计不同的一点是Binder IPC中采用了“线程池”的服务端模型。也就是说在服务端中Binder的用户态和内核会有一个响应线程池的概念。当某个客户端进程发起通信时内核会从服务端的线程池中选择一个可用的线程来响应。这种设计能够在同步进程间通信的情况下比较好地处理并发的通信请求。本文节选自《现代操作系统原理与实现》第7章操作系统和系统安全领域国际知名学者、上海交通大学陈海波、夏虞斌领衔撰写本书是作者在复旦大学和上海交通大学十余年操作系统教学经验的科学总结由浅入深介绍现代操作系统经典理论与方法。结合前沿研究与工业界实践面向真实场景与真实问题。