进程间通信

本文详细探讨了进程间通信的必要性,包括进程空间独立的挑战及解决办法。介绍了信号、管道、消息队列、共享内存和信号量等通信方式,以及它们的原理、实现和应用场景。重点突出了信号的异步特性,管道的单向通信,共享内存的高效传输,以及信号量在资源保护中的作用。最后概述了跨主机通信的套接字技术。
摘要由CSDN通过智能技术生成

进程间通信

1、为什么要进程间通信(进程空间地址独立),如何实现进程间通信(找中间人)

        因为进程的空间独立(逻辑上),每开辟一个进程,内核就创建一个虚拟的内存的地址空间(开销大),方便用户对内存的随意读写,保证程序的健壮性,不受破坏(病毒或其他程序)。除了以上进程的优点外,因为进程空间地址上的独立,进程创建和调度会带来很大的开销,并且彼此之间无法通信。为了实现进程间信息的交互和状态的传递,所以要进行进程间通信。

        进程间通信的原理就是,OS作为所有进程共享的第三方,会提供相关的机制(文件、内存映射、内和开辟空间),以实现进程间数据的转发,达到数据共享的目的。(广义上还可以用文件编程方式进行通信)

2、通信的方式

      进程间通信方式                                         实现原理
           信号信号是一种向进程发送通知,告诉其某件事情发生了的一种简单通信机制,只发信号,不传送数据
           管道管道是在内核创建一个单向读写(不能同时读写)的文件
        消息队列消息队列的本质就是由内核创建的用于存放消息的链表,由于是存放消息的,所以我们就把这个链表称为消息队列。
        共享内存让同一块物理内存被映射到进程A、B各自的进程地址空间。进程A可以即时看到进程B对共享内存中数据的更新
          信号量当多个进程/线程进行共享操作时,用于资源保护,以防止出现相互干扰的情况
    套接字(待补充)实现跨网络不同主机间的通信

3、信号(只发信号,不传输数据)

         Linux系统定义了一些宏(相当于约定好的暗号),实质上都是一些整数编号,通过发送暗号说明当前进程做了什么事。

        (1)信号的产生方式

                a\另一个进程发送信号

                b\内核发送信号 硬件发

                c\底层硬件发送

       (2)信号的处理方式  

                a\默认执行方式       

                b\忽略信号(有的信号不能忽略)

                c\自定义执行用户需要的动作(自己写函数)

       (3)信号的屏蔽字(用来屏蔽信号的)

                屏蔽字就是一个64位的无符号整数,每一位对应着一个信号,如果这一位为0,表示信号可以被立即处理,如果为1表示该信号被屏蔽了,通过API能修改(位运算)

       (4)未处理信号集(记录没处理的信号)

                跟屏蔽字一样,也一个64位的无符号整形数(看对应为状态0或1),专门用于记录未处理的信号,记下没处理的,不屏蔽就通知去做

       (5)信号的特点:

                        a\异步通信(随时可以发信号,实时性好)

                        b\ 只发信号,不传数据

                        c\优化进程等待(原来同步方式改成了异步)

4、管道(无格式存储)

         分类                                                   特点
        无名管道  1、亲缘进程间通信;2、单向通信;3、数据读出就被删除;4、读管道时,如果没有数据的话,读操作会休眠(阻塞),写数据时,缓冲区写满会休眠(阻塞)
    有名管道(FIFO)

 相当于给无名管道加了个名(创建和使用方式发生了很大变化),可以通过文件名找到这个管道,实现任意进程间通信

1、无名管道        

2、有名管道

3、注意:1、有名管道用 mkfifo 创建(用户空间),不能用open创建;

                   2、要保证管道不被重复创建,单个进程创建要保证进程运行顺序

                   3、单向读取数据(想要实现双向可以创建两个管道),不能以读写方式打开命名管道FIFO文件

4、管道应用:1、大多应用于小数据传输数据

                  2、shell中用管道作为输入输出的重定向

                  3、亲缘关系的进程间通信

5、消息队列(有格式,网状结构通信传输数据使用)

        消息对列是由内核创建的链表,结点中保存信息(结构体,包含编号和信息内容),相比管道拥有更好的灵活性,消息有格式,有类型可以作为优先级使用,可在任意进程间复用,因为是随内核持续的,所以生命力更强,应用空间更大(注意删除)

        1、对消息队列的操作类型:

        (1)打开创建消息对列(ftok函数生成键值,相当于对应系统的—条路经>msgget函数创建获得描述字 一个整数,用来作为找到这个消息队列)

        (2)读写操作(msgrcv读&msgsed发)

        (3)获取或设置消息对列的属性msgctl

   

        2、消息队列的限制:(1)每个消息队列的容量(所能容纳的字节数)有限制

                                          (2)消息队列所能容纳的最大消息数

        3、应用场景:

               (1)传送有格式的信息流

               (2)多进程网状交叉通信时用消息队列最好

               (3)实现大规模数据传输

6、共享内存(内存映射或内存共享机制实现,速度最快,大数据传输)

        1、实现原理

        内存映射(mmap函数映射)或内存共享机制(system V提供)实现

        2、API

        3、共享内存实现的步骤(system V)        

        (1)进程调用shmget函数创建新的或获取已有共享内存;

        (2)进程调用shmat函数,将物理内存映射到自己的进程空间;

        (3)shmdt函数,取消映射

        (4)调用shmctl函数释放开辟的那片物理内存空间

        4、特点:

                         (1)减少了进入内核空间的次数

                         (2)直接使用地址来读写内存,效率更高,适用于大数据量的传输

        5、注意事项        

        6、应用场景        大数据传输

 7、信号量(信号锁,和信号没关系,实现共享资源的保护,同步和互斥)

        当多个进程/线程进行共享操作时,让进程互斥或同步访问共享资源,用于资源保护,不用做存储通信数据。

进程之间存在两种基本关系:竞争关系和协作关系。

        进程的互斥、同步、通信都是基于这两种基本关系而存在的。

        为了解决进程间竞争关系(间接制约关系)而引入进程互斥;

        为了解决进程间松散的协作关系(直接制约关系)而引入进程同步;

        为了解决进程间紧密的协作关系而引入进程通信。

        1、信号量实现的内容

        (1)互斥:对于互斥操作来说,多进程共享操作时,多个进程间不关心谁先操作、谁后操作的先后顺序问题,它们只关心一件事,那就是我在操作时别人不能操作(进程之间没有直接制约关系,都可以对共享资源操作,用到互斥)

        (2)同步:所以所谓同步就是,多个共享操作时,进程必须要有统一操作的步调,按照一定的顺序来操作(进程间有直接制约关系,即必须让一个进程执行完,另一个进程才能执行,需要同步)

        2、信号量分类

        二值信号量        信号量资源被获取了,信号量值就是 0,信号量资源被释放,信号量值就是 1,把这种只有 0 和1 两种情况的信号量称之为二值信号量

        多值信号量

        4、信号量集(实际创建创一个集合来用)

        信号量其实是一个内核创建的,供相关进程共享的整形变量,只不过我们在调用相关API创建信号量时,我们创建的都是一个信号量集合,所谓集合就是可能会包含好多个信号量。用于互斥时,集合中只包含一个信号量,用于同步时,集合中会包含多个信号量,至于多少个,需要看情况。

        5、信号量的使用步骤

        6、API

        7、应用注意事项主要(应用于进程间的同步)

        (1)同步时有多少个进程需要同步,我们在集合中就需要创建对应数量的信号量

        (2)注意上锁解锁的时间和顺序,结合其他通信方式优化程序

   

8、总结

凉了!张三同学没答好「进程间通信」,被面试官挂了...._小林coding-CSDN博客

   由于每个进程的用户空间都是独立的,不能相互访问,这时就需要借助内核空间来实现进程间通信,原因很简单,每个进程都是共享一个内核空间。

            信号    与信号量名字很相似,但功能一点儿都不一样。信号是进程间通信机制中唯一的异步通信机制,信号可以在应用进程和内核之间直接交互,内核也可以利用信号来通知用户空间的进程发生了哪些系统事件。信号事件的来源主要有硬件来源(如键盘 Cltr+C )和软件来源(如 kill 命令),一旦有信号发生,进程有三种方式响应信号 1. 执行默认操作、2. 捕捉信号、3. 忽略信号。有两个信号是应用进程无法捕捉和忽略的,即 SIGKILL 和SEGSTOP,这是为了方便我们能在任何时候结束或停止某个进程。

        匿名管道        顾名思义,它没有名字标识,匿名管道是特殊文件只存在于内存,没有存在于文件系统中,shell 命令中的「|」竖线就是匿名管道,1、通信的数据是无格式的流并且大小受限;2、通信的方式是单向的,数据只能在一个方向上流动,如果要双向通信,需要创建两个管道;3、匿名管道是只能用于存在父子关系的进程间通信;4、匿名管道的生命周期随着进程创建而建立,随着进程终止而消失。

        命名管道        突破了匿名管道只能在亲缘关系进程间的通信限制,因为使用命名管道的前提,需要在文件系统创建一个类型为 p 的设备文件(有名,可以查找),那么毫无关系的进程就可以通过这个设备文件进行通信。另外,不管是匿名管道还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据时候自然也是从内核中获取,同时通信数据都遵循先进先出原则,不支持 lseek 之类的文件定位操作。(消息队列实现)

        消息队列        克服了管道通信的数据是无格式的字节流的问题,消息队列实际上是保存在内核的「消息链表」,消息队列的消息体是可以用户自定义的数据类型(结构体),发送数据时,会被分成一个一个独立的消息体,当然接收数据时,也要与发送方发送的消息体的数据类型保持一致,这样才能保证读取的数据是正确的。消息队列通信的速度不是最及时的,毕竟每次数据的写入和读取都需要经过用户态与内核态之间的拷贝过程。

        共享内存        可以解决消息队列通信中用户态与内核态之间数据拷贝过程带来的开销,它直接分配一个共享空间,每个进程都可以直接访问,就像访问进程自己的空间一样快捷方便,不需要陷入内核态或者系统调用,大大提高了通信的速度,享有最快的进程间通信方式之名。但是便捷高效的共享内存通信,带来新的问题,多进程竞争同个共享资源会造成数据的错乱。(信号量解决)

        信号量    保护共享资源,以确保任何时刻只能有一个进程访问共享资源(互斥);保证多个进程共享操作时,必须要有统一操作的步调即顺序操作共享内存(同步)。信号量本质上是OS创建的一个共享变量,进程在进行操作之前,会先检查这个变量的值,这变量的值就是一个标记,通过这个标记就可以知道可不可以操作,以实现互斥。

        前面说到的通信机制,都是工作于同一台主机,如果要与不同主机的进程间通信,那么就需要 Socket 通信了。Socket 实际上不仅用于不同的主机进程间通信,还可以用于本地主机进程间通信,可根据创建 Socket 的类型不同,分为三种常见的通信方式,一个是基于 TCP 协议的通信方式,一个是基于 UDP 协议的通信方式,一个是本地进程间通信方式。

        以上,就是进程间通信的主要机制了。你可能会问了,那线程通信间的方式呢?

        同个进程下的线程之间都是共享进程的资源,只要是共享变量都可以做到线程间通信,比如全局变量,所以对于线程间关注的不是通信方式,而是关注多线程竞争共享资源的问题,信号量也同样可以在线程间实现互斥与同步:

    互斥的方式,可保证任意时刻只有一个线程访问共享资源;
    同步的方式,可保证线程 A 应在线程 B 之前执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

碳水生活

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值