操作系统核心原理-3.进程原理(下):进程通信

进程作为人类的发明,自然也免不了脱离人类的习性,也有通信的需求。如果进程之间不进行任何通信,那么进程所能完成的任务就要大打折扣。人类的通信方式无外乎对白(通过声音沟通)、打手势、写信、发电报、拥抱等方法。同理,进程也可以通过同样的方式来进行通信。本篇我们就来看看进程的这些交互方式。

一、进程对白:管道、套接字

  人们最常用的通信手段就是对白,一方发出声音,另一方接收声音。而声音的传递需要通过一些介质,例如:空气(face to face)、线缆(有线电话)等。类似的,进程对白就是一个进程发出某种数据信息,另外一方接收数据信息,而这些数据信息通过一片共享的存储空间进行传递。

1.1 管道

一个进程向存储空间的一端写入信息,另一个进程存储空间的另外一端读取信息,这个就是管道。就像两个人对白的媒介是空气也可以是线缆一样,管道所占的空间既可以是内存也可以是磁盘。

  要创建一个管道,一个进程只需要调用管道创建的系统调用即可,该系统调用所做的事情就是在某种存储介质上划出一片空间,赋给其中一个进程写的权利,另一个进程读的权利即可。

  例如在Linux下,我们通过Shell命令输入两个命令,中间通过符号“|”来创建两个命令之间的管道:

$ sort < file1 | grep zou

  上面一个命令表示:对file1的内容首先进行排序,排序完成后的结果将作为grep的输入,在结果里面找出所有包括字符串zou的文本行。也就是说,在两个任务“排序“(sort)和”查找”(grep)之间创建了一个管道,数据从sort流向了grep。

1.2 套接字

  套接字(Socket)的功能非常强大,可以支持不同层面、不同应用、跨网络的通信。使用套接字进行通信需要双方均创建一个套接字,其中一方作为服务器方,另外一方作为客户方。服务器方必须首先创建一个服务区套接字,然后在该套接字上进行监听,等待远方的连接请求。客户方也要创建一个套接字,然后向服务器方发送连接请求。服务器套接字在受到连接请求之后,将在服务器方机器上新建一个客户套接字,与远方的客户方套接字形成点到点的通信通道。之后,客户方和服务器方便可以直接通过类似于send和recv的命令在这个创建的套接字管道上进行交流了。

  例如,在C#中我们可以轻松地创建一个服务器方的Socket:

    // 创建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.3 不足之处

  (1)必须首先在通信的进程间建立连接(管道或套接字),这需要消耗系统资源;

  (2)通信是自愿的,而管道和套接字需要强制双方进行通信;

  (3)由于建立连接需要消耗时间,一旦建立就应该尽可能多的通信,如果通信信息量很小,则就是“杀鸡用牛刀”了;

二、进程电报与旗语:信号与信号量

2.1 电报:信号

  信号类似于我们生活中的电报,如果你想给某人发一封电报,就拟好电文,然后将报文和收报人的信息都交给电报公司。电报公司则将电报发送到收报人所在地的邮局,并通知收报人来取电报。其中,发报文时无需收报人实现知道,也无需进行任何协调。如果对方选择不对信号做出响应,则将被OS终止运行。

  在计算机中,信号就是一个内核对象或者是一个内核数据结构。发送方将该数据结构的内容填好,并指明该信号的目标进程后,发出特定的软件中断(这就是一个发电报的操作)。OS接收到特定的中断请求后,知道是有进程要发送信号,于是到特定的内核数据结构里查找信号接收方,并进行通知。接到通知的进程则对信号进行相应处理。

2.2 旗语:信号量

  信号量来源于铁路的运行:在一条单轨铁路上,任何时候只允许有一列火车行驶在该铁路上,而管理这条铁路的系统就是信号量。任何一列火车必须等到表明该铁路可以行驶的信号后才能进入轨道。当列车进入后,需要将信号改为禁止状态进入来防止别的列车同时进入。而当列车驶出单轨后,则需要将信号变回允许进入状态,这很像以前的旗语。当然,通过联想到我们实际开发中经常用的锁,这就更容易理解了。

  在计算机中,信号量实际上就是一个简单整数。一个进程在信号变为0或1的情况下推进,并将信号变为1或0来防止别的进程同时推进。当该进程完成任务后,则将信号再改为0或1,从而允许其他进程执行。从而我们也可以看出,信号量已经不只是一种通信机制,更是一种同步机制

三、进程拥抱:共享内存

  前面通过对话、发电报、旗语已经满足了多种通信需要,但是当两个进程要共享大量数据时就没法十分满足需求。就如同两个坠入爱河的骚年,它们互相喜欢并想要在一起同居(共享大量数据),这时打电话、发电报、握手对话就显得不够了。这时候,它们需要的就是拥抱,只有紧紧拥抱才能尽可能地共享,feeling so good!

3.1 共享内存

  进程的拥抱就是共享内存,两个进程共同拥有同一片内存。对于这片内存中的任何内容,二者均可以访问。要使用共享内存进行通信,进程A首先需要创建一片内存空间作为通信用,而其他进程B则将片内存映射到自己的(虚拟)地址空间。这样,进程A读写自己地址空间中对应共享内存的区域时,就是在和进程B进行通信。

3.2 不足之处

  (1)使用共享内存机制通信的两个进程必须在同一台物理机上;

  (2)安全性脆弱,假如一个进程有病毒,会很容易传给另外一个进程;

四、信件发送:消息队列

  消息队列是一列具有头和尾的消息排列,新来的消息放在队列尾部,而读取消息则从队列头部开始,如下图所示:

  这样看来,它和管道十分类似,一头读,一头写?的确,看起来很像管道,但又不是管道:

  (1)消息队列无固定的读写进程,任何进程都可以读写;而管道需要指定谁读和谁写;

  (2)消息队列可以同时支持多个进程,多个进程可以读写消息队列;即所谓的多对多,而管道是点对点;

  (3)消息队列只在内存中实现,而管道还可以在磁盘上实现;

参考资料

邹恒明,《操作系统之哲学原理》,机械工业出版社

作者:周旭龙

出处:http://edisonchou.cnblogs.com

本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文链接。

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏移动端周边技术扩展

fuck thefuck安装使用

33350
来自专栏java一日一条

Python爬虫爬取美剧网站

一直有爱看美剧的习惯,一方面锻炼一下英语听力,一方面打发一下时间。之前是能在视频网站上面在线看的,可是自从广电总局的限制令之后,进口的美剧英剧等貌似就不在像以前...

22920
来自专栏架构之路

超清晰的makefile解释、编写与示例

Makefile范例教学 Makefile和GNU make可能是linux世界里最重要的档案跟指令了。编译一个小程式,可以用简单的command来进行编译;稍...

58280
来自专栏我是攻城师

图形数据库之Neo4j学习(一)

44250
来自专栏编程微刊

highcharts中的x轴如何显示时分秒时间格式

上一篇文章写道:三分钟上手Highcharts简易甘特图:https://www.jianshu.com/p/d669d451711b,在官方文档里面,x轴默认...

29220
来自专栏数据小魔方

R语言数据重塑及导出操作

今天跟大家简单介绍下几个常用的R数据操纵技巧——导入(xlsx)、导出及长宽转换! 数据导入(xlsx) 之前写过一篇关于R导入不同类型数据的方式,但是其中只涉...

27730
来自专栏塔奇克马敲代码

Windows平台下源码分析工具

25730
来自专栏小巫技术博客

应用被强杀了怎么办

11220
来自专栏吉浦迅科技

DAY64:阅读 Memory Model

我们正带领大家开始阅读英文的《CUDA C Programming Guide》,今天是第64天,我们正在讲解CUDA C语法,希望在接下来的36天里,您可以学...

8330
来自专栏塔奇克马敲代码

Windows平台下源码分析工具

24630

扫码关注云+社区

领取腾讯云代金券