计算机理论/进程间通信

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_39591494/article/details/89067251

进程间通信:


  进程间通信(IPC, Inter-Process Communication)是指在不同的进程之间,相互传播或交换信息。IPC的方式通常有管道(包括无名管道和命名管道)消息队列、信号量、共享存储、socket、streams等…
通过以上所述,进程间的通信分为:本地、远程。

本地进程间通信:

本地的程序之间交互:
从QQ复制一张图片到Wechat
在这里插入图片描述
在这里插入图片描述

远程进程的通信:

什么是进程?

  进程是具有一定独立功能的程序关于某个数据集合上的一次运行活动进程是系统进行资源分配和调度的一个独立单元。 每个进程都有自己的独立内存空间,不同的进程通过进程间通信来通信。(有一个程序在一堆数据上进行了一堆操作)。

进程间通信的几种类型

管道:通常指无名管道,是UNIX系统IPC最古老的形式。
1、它是半双工的(数据只能在一个方向上流动),具有固定的读端和写端。
2、它只能用于具有亲缘关系的进程之间通信(也是父子进程或者兄弟进程之间)。
3、它可以看成是一种特殊的文件,对于它的读写也可以使用普通的readwrite函数。但是它不是普通的文件,并不属于其他任何文件系统,并且只存在于内存当中。 通过系统函数int pipe (int _pipedes[2])进行创建。


FIFO,命名管道:一种特殊的文件类型
1、FIFO可以在无关的进程之间交换数据,与无名管道不同。
2、FIFO有路径名誉之相关联,它以一种特殊的设备文件形式存在于文件系统中。 命名管道,FIFO,是一种特殊的文件类型。
命名管道由mkfifo函数创建打开用open,FIFO与PIPE(匿名管道)之间唯一的区别在它们创建与打开的方式不同,这些工作完成之后,它们具有相同的语义。


消息队列:
消息队列,是消息的链接表,存放在内核中。 一个消息队列由一个表示符:(队列的ID)来标识。
1、消息队列的面向记录的,其中的消息具有特定的格式以及特定的优先级。
2、消息队列独立于发送与接收进程,进程终止的时候消息队列及其内容不会被删除。 消息队列可以实现消息的随机查询,消息不一定要以先进先出的次序读取,也可以按消息的类型读取。


信号量
信号量(semaphore)与以上IPC结构不同,它是一个计数器。信号量用于实现进程间的互斥与同步,而不是用于存储进程间的通信数据。
1、信号量用于进程间的同步,若要在进程间传递数据需要结合共享内存。
2、信号量基于操作系统的PV操作,程序对信号量的操作都是原子操作。
3、每次对信号量的PV操作不仅仅限于对信号量的+1或者-1 而且可以加减任意的正整数。
4、支持信号量组。


共享内存
共享内存(Shared Memory)指两个或者多个进程共享一个给定的存储区。
1、共享内存是最快的一种IPC,因为进程是直接对内存进行存取。
2、因为多个进程可以同时操作,所以需要进行同步。
3、信号量+共享内存通常结合在一起使用,信号量用来同步对共享内存的访问。

进程的基本特征:

动态性
进程的状态和转换
在这里插入图片描述
进程控制块
进程控制块(Processing Controk Block)也称为进程描述快(Process Descriptor)是操作系统核心中的一种数据结构,主要表示进程状态。在创建进程的时候,首先建立PCB,它伴随进程运行的全过程,直到进程撤销而报销。系统可以利用PCB来控制和管理进程,所以PCB是系统的感知进程存在的唯一标识。

UNIX系统中的几个进程控制操作:

  • Fork():通过复制调用进程来建立新的进程,是最基本的进程建立过程。
  • exec():包括一系列系统调用,它们是通过用一段新的程序代码覆盖原来的地址空间,实现进程执行代码的转换。
  • wait():提供初级的进程同步操作,能使一个进程等待另外一个进程的结束。
  • exit():用来终止一个进程的执行。

在这里插入图片描述

进程和线程之由来?

操作系统中为什么会出现进程?
说起进程的由来,我们需要从操作系统的发展历史谈起。

  也许在今天,我们无法想象在很多年以前计算机是什么样子。我们现在可以用计算机来做很多事情:办公、娱乐、上网,但是在计算机刚出现的时候,是为了解决数学计算的问题,因为很多大量的计算通过人力去完成是很耗时间和人力成本的。在最初的时候,计算机只能接受一些特定的指令,用户输入一个指令,计算机就做一个操作。当用户在思考或者输入数据时,计算机就在等待。显然这样效率和很低下,因为很多时候,计算机处于等待用户输入的状态。

  那么能不能把一系列需要操作的指令预先写下来,形成一个清单,然后一次性交给计算机,计算机不断地去读取指令来进行相应的操作?就这样,批处理操作系统诞生了。用户可以将需要执行的多个程序写在磁带上,然后交由计算机去读取并逐个地执行这些程序,并将输出结果写到另一个磁带上。

  虽然批处理操作系统的诞生极大地提高了任务处理的便捷性,但是仍然存在一个很大的问题:

  假如有两个任务A和B,任务A在执行到一半的过程中,需要读取大量的数据输入(I/O操作),而此时CPU只能静静地等待任务A读取完数据才能继续执行,这样就白白浪费了CPU资源。人们于是想,能否在任务A读取数据的过程中,让任务B去执行,当任务A读取完数据之后,让任务B暂停,然后让任务A继续执行?

  但是这样就有一个问题,原来每次都是一个程序在计算机里面运行,也就说内存中始终只有一个程序的运行数据。而如果想要任务A执行I/O操作的时候,让任务B去执行,必然内存中要装入多个程序,那么如何处理呢?多个程序使用的数据如何进行辨别呢?并且当一个程序运行暂停后,后面如何恢复到它之前执行的状态呢?

  这个时候人们就发明了进程,用进程来对应一个程序,每个进程对应一定的内存地址空间,并且只能使用它自己的内存空间,各个进程间互不干扰。并且进程保存了程序每个时刻的运行状态,这样就为进程切换提供了可能。当进程暂时时,它会保存当前进程的状态(比如进程标识、进程的使用的资源等),在下一次重新切换回来时,便根据之前保存的状态进行恢复,然后继续执行。

这就是并发,能够让操作系统从宏观上看起来同一个时间段有多个任务在执行。换句话说,进程让操作系统的并发成为了可能。

注意,虽然并发从宏观上看有多个任务在执行,但是事实上,任一个具体的时刻,只有一个任务在占用CPU资源(当然是对于单核CPU来说的)

为什么会出现多线程?
  在出现了进程之后,操作系统的性能得到了大大的提升。虽然进程的出现解决了操作系统的并发问题,但是人们仍然不满足,人们逐渐对实时性有了要求。因为一个进程在一个时间段内只能做一件事情,如果一个进程有多个子任务,只能逐个地去执行这些子任务。比如对于一个监控系统来说,它不仅要把图像数据显示在画面上,还要与服务端进行通信获取图像数据,还要处理人们的交互操作。如果某一个时刻该系统正在与服务器通信获取图像数据,而用户又在监控系统上点击了某个按钮,那么该系统就要等待获取完图像数据之后才能处理用户的操作,如果获取图像数据需要耗费10s,那么用户就只有一直在等待。显然,对于这样的系统,人们是无法满足的。

  那么可不可以将这些子任务分开执行呢?即在系统获取图像数据的同时,如果用户点击了某个按钮,则会暂停获取图像数据,而先去响应用户的操作(因为用户的操作往往执行时间很短),在处理完用户操作之后,再继续获取图像数据。人们就发明了线程,让一个线程去执行一个子任务,这样一个进程就包括了多个线程,每个线程负责一个独立的子任务,这样在用户点击按钮的时候,就可以暂停获取图像数据的线程,让UI线程响应用户的操作,响应完之后再切换回来,让获取图像的线程得到CPU资源。从而让用户感觉系统是同时在做多件事情的,满足了用户对实时性的要求。

  换句话说,进程让操作系统的并发性成为可能,而线程让进程的内部并发成为可能。但是要注意,一个进程虽然包括多个线程,但是这些线程是共同享有进程占有的资源和地址空间的。进程是操作系统进行资源分配的基本单位,而线程是操作系统进行调度的基本单位。

以上部分内容来自:http://www.cnblogs.com/dolphin0520/p/3910667.html

猜你喜欢

转载自blog.csdn.net/qq_39591494/article/details/89067251