进程通信

作者: 贪婪的君子 | 来源:发表于2017-05-22 21:43 被阅读64次

    Hey,Guys! 给我发条消息吧?

    我们知道,无论是在进程互斥还是进程同步中,所有的进程都交换了消息——一个简单的唤醒信号。
    虽然只是一个简单的消息,但我们依旧可以将其划分到进程通信中,作为一种低级通信看待(蚊子再小也是肉嘛!)。
    有低级通信,那自然也就有高级通信,不过一般而言,我们所说的进程通信都是指高级通信,毕竟互斥和同步都有自己专属的称呼。

    进程通信


    进程间的互斥,同步以及信息交换统称为进程通信

    进程通信的模式

    1. 共享内存模式
    • 相互通信的进程之间有公共内存,这个公共内存是操作系统分配和管理的,而其使用和基于此的信息传递则是相互通信的进程自己完成的。
    • 由于是基于公共内存,故而对其访问需要提供必要的同步机制(等价于共享变量)。

    小的时候做过一个传声器,两个纸杯加上一根绳子就可以制作了,但问题就是两个纸杯共用一根绳子,我和朋友只能是一个说,一个听,要不然就听不到对方再说什么了。

    1. 消息传递模式
       
      在此种模式下的信息传递是不需要公共内存的。操作系统提供提供发送命令(send)和接收命令(receive)这两个系统调用命令来进行消息传递(通信)。

    发生消息传递时,只需通信的进程调用这两个命令即可。由于这两个命令是由操作系统提供的,所以命令内部的实现对于用户是透明的。
    就像我们打电话,只需要会打电话,会接电话就好了,除了研究这个技术的人,谁会关心怎么实现的这个技术呢?

    基于消息传递的实现

    直接方式

    在这种方式下,进程会直接指定消息源或者接受方,类似于函数的映射,有一对一和多对一的类型。

    • 一对一,即对称形式


      对称形式
    • 多对一,即非对称形式


      非对称形式

    高中学数学,最痛苦的就是函数的映射关系,开始的时候一看,哎呀,挺简单的,理解了,然后老师上课提问映射的关系......
    咦?映射,什么玩意儿?!
    浑浑噩噩一个学期之后,什么1-1映射,慢射之类的,还是挺模糊的,不懂,于是就听同桌说,画个函数图像啦,balabala一堆之后,终于懂了。
    于是整个高中三年,遇到映射就画个图像......

    消息传送的途经

    1. 带缓冲的途经
      高级语言进行文件读写的时候似乎都有带缓冲和不带缓冲的读写?带缓冲流程序开销小,这是由于不需要频繁的进入磁盘读取文件,进程的消息传递也是这样的。


      带缓冲的send和receive的具体实现

    send和receive命令都是操作系统提供的,使用的时候是要进入操作系统的,而这两者进入操作系统是靠进程产生的自愿性中断实现的。而且有个缓冲区,只需中断一次,读取完消息,回到用户态就可以继续向下执行其他的程序,不用不断的中断读取,直到读取完毕。

    1. 不带缓冲


      不带缓冲的send和receive的具体实现

    这看其来可比带缓冲的简单太多了,而且没有了缓冲区,也就节省了空间,但是由于要等待接收进程完成消息接收后才能让发送进程继续推进,这样看来并发性着实太弱了。

    间接方式

    间接方式和直接方式相对应,是存在媒介进行信息的交换——通信,不需要指明进程具体是哪一个,只需要指明相互通信的进程使用的中间媒介。
    这个中间媒介在操作系统中被描述为信箱,所以间接方式也成为信箱方式,在实现这种方式时,信箱既可以属于操作系统空间,也可以是属于用户进程空间,但关于信箱操作的命令则是操作系统提供的(系统调用命令),属于操作系统,来看看关于信箱的定义:

    typedef struct mailbox
    {
        int in, out;      //读写内容的位置,初始为0
        int k;      //消息的个数
        semaphore s1, s2;     //协调发送和接收的信号量初始为k和0
        semaphore mutex;    //用于各进程进入信箱的互斥
        message letter[k];         //信箱,保存k个消息
    }MailBox;
    

    对于信箱的操作定义:

    send_MB(MailBox A, message M)
    {
        P(A.s1);
        P(A.mutex);
        A.letter[A.in] = M;
        A.in = (A.in + 1) % A.k;
        V(A.mutex);
        V(A.s2);
    }
    
    receive_MB(MailBox A, message N)
    {
        P(A.s2);
        P(A.mutex);
        N = A.letter[A.out];
        A.out = (A.out + 1) % A.k;
        V(A.mutex);
        V(A.s1);
    }
    

    send_MB和receive_MB只是关于信箱的四个命令之一,因为还要创建和删除嘛!


    信箱命令的使用权限

    话说,朋友之间吵架冷战算是很正常的事情吧?
    我上高中那会儿和同桌不知道因为啥原因吵了一架,然后就开始冷战,到后来一次班上六人一组讨论问题(我们开玩笑说这是圆桌会议),关于一个问题又出现分歧,然后我就伸手随便拉住某个人说:“她是不是傻!alabala.....”,我同桌又拽着他:“你告诉他,这么简单的逻辑问题都出错,明显是他傻!”......
    想想那兄弟可能也挺无奈的,你说两人都能听到对方说话,还非要找第三人来当传声筒......

    小结


    在进程通信的模式选择上,没有完美,只有适合于不适合,即便我们说无缓冲的通信并发性差,开销还大,但是耐不住人家实现简单啊,在一些简单的问题实现上和带缓冲的通信差距并不大,那为何要选择带缓冲的通信方式呢?杀鸡焉用牛刀?
    这条经验,不仅仅适用于进程通信上,几乎什么事情,这条经验都是实用的。

    Hey! Guys! 我发了条消息给你,收到了吗?

    相关文章

      网友评论

        本文标题:进程通信

        本文链接:https://www.haomeiwen.com/subject/mqbixxtx.html