进程做为人类的发明,天然也免不了脱离人类的习性,也有通讯的需求。若是进程之间不进行任何通讯,那么进程所能完成的任务就要大打折扣。人类的通讯方式无外乎对白(经过声音沟通)、打手势、写信、发电报、拥抱等方法。同理,进程也能够经过一样的方式来进行通讯。本篇咱们就来看看进程的这些交互方式。安全
人们最经常使用的通讯手段就是对白,一方发出声音,另外一方接收声音。而声音的传递须要经过一些介质,例如:空气(face to face)、线缆(有线电话)等。相似的,进程对白就是一个进程发出某种数据信息,另一方接收数据信息,而这些数据信息经过一片共享的存储空间进行传递。服务器
一个进程向存储空间的一端写入信息,另外一个进程存储空间的另一端读取信息,这个就是管道。就像两我的对白的媒介是空气也能够是线缆同样,管道所占的空间既能够是内存也能够是磁盘。网络
要建立一个管道,一个进程只须要调用管道建立的系统调用便可,该系统调用所作的事情就是在某种存储介质上划出一片空间,赋给其中一个进程写的权利,另外一个进程读的权利便可。数据结构
例如在Linux下,咱们经过Shell命令输入两个命令,中间经过符号“|”来建立两个命令之间的管道:socket
$ sort < file1 | grep zou
上面一个命令表示:对file1的内容首先进行排序,排序完成后的结果将做为grep的输入,在结果里面找出全部包括字符串zou的文本行。也就是说,在两个任务“排序“(sort)和”查找”(grep)之间建立了一个管道,数据从sort流向了grep。spa
套接字(Socket)的功能很是强大,能够支持不一样层面、不一样应用、跨网络的通讯。使用套接字进行通讯须要双方均建立一个套接字,其中一方做为服务器方,另一方做为客户方。服务器方必须首先建立一个服务区套接字,而后在该套接字上进行监听,等待远方的链接请求。客户方也要建立一个套接字,而后向服务器方发送链接请求。服务器套接字在受到链接请求以后,将在服务器方机器上新建一个客户套接字,与远方的客户方套接字造成点到点的通讯通道。以后,客户方和服务器方即可以直接经过相似于send和recv的命令在这个建立的套接字管道上进行交流了。操作系统
例如,在C#中咱们能够轻松地建立一个服务器方的Socket:3d
// 建立Socket->绑定IP与端口->设置监听队列的长度->开启监听链接 socketWatch = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp); socketWatch.Bind(new IPEndPoint(IPAddress.Parse(txtIPAddress.Text), int.Parse(txtPort.Text))); socketWatch.Listen(10);
(1)必须首先在通讯的进程间创建链接(管道或套接字),这须要消耗系统资源;code
(2)通讯是自愿的,而管道和套接字须要强制双方进行通讯;对象
(3)因为创建链接须要消耗时间,一旦创建就应该尽量多的通讯,若是通讯信息量很小,则就是“杀鸡用牛刀”了;
信号相似于咱们生活中的电报,若是你想给某人发一封电报,就拟好电文,而后将报文和收报人的信息都交给电报公司。电报公司则将电报发送到收报人所在地的邮局,并通知收报人来取电报。其中,发报文时无需收报人实现知道,也无需进行任何协调。若是对方选择不对信号作出响应,则将被OS终止运行。
在计算机中,信号就是一个内核对象或者是一个内核数据结构。发送方将该数据结构的内容填好,并指明该信号的目标进程后,发出特定的软件中断(这就是一个发电报的操做)。OS接收到特定的中断请求后,知道是有进程要发送信号,因而到特定的内核数据结构里查找信号接收方,并进行通知。接到通知的进程则对信号进行相应处理。
信号量来源于铁路的运行:在一条单轨铁路上,任什么时候候只容许有一列火车行驶在该铁路上,而管理这条铁路的系统就是信号量。任何一列火车必须等到代表该铁路能够行驶的信号后才能进入轨道。当列车进入后,须要将信号改成禁止状态进入来防止别的列车同时进入。而当列车驶出单轨后,则须要将信号变回容许进入状态,这很像之前的旗语。固然,经过联想到咱们实际开发中常常用的锁,这就更容易理解了。
在计算机中,信号量实际上就是一个简单整数。一个进程在信号变为0或1的状况下推动,并将信号变为1或0来防止别的进程同时推动。当该进程完成任务后,则将信号再改成0或1,从而容许其余进程执行。从而咱们也能够看出,信号量已经不仅是一种通讯机制,更是一种同步机制。
前面经过对话、发电报、旗语已经知足了多种通讯须要,可是当两个进程要共享大量数据时就无法十分知足需求。就如同两个坠入爱河的骚年,它们互相喜欢并想要在一块儿同居(共享大量数据),这时打电话、发电报、握手对话就显得不够了。这时候,它们须要的就是拥抱,只有牢牢拥抱才能尽量地共享,feeling so good!
进程的拥抱就是共享内存,两个进程共同拥有同一片内存。对于这片内存中的任何内容,两者都可以访问。要使用共享内存进行通讯,进程A首先须要建立一片内存空间做为通讯用,而其余进程B则将片内存映射到本身的(虚拟)地址空间。这样,进程A读写本身地址空间中对应共享内存的区域时,就是在和进程B进行通讯。
(1)使用共享内存机制通讯的两个进程必须在同一台物理机上;
(2)安全性脆弱,假如一个进程有病毒,会很容易传给另一个进程;
消息队列是一列具备头和尾的消息排列,新来的消息放在队列尾部,而读取消息则从队列头部开始,以下图所示:
这样看来,它和管道十分相似,一头读,一头写?的确,看起来很像管道,但又不是管道:
(1)消息队列无固定的读写进程,任何进程均可以读写;而管道须要指定谁读和谁写;
(2)消息队列能够同时支持多个进程,多个进程能够读写消息队列;即所谓的多对多,而管道是点对点;
(3)消息队列只在内存中实现,而管道还能够在磁盘上实现;
邹恒明,《操做系统之哲学原理》,机械工业出版社