10.进程间通信 1.管道 所谓的管道,就是内核里面的一串缓存,从管道的一端写入的数据,实际上是缓存在内核中的,另一端读取,也就是从内核中读取这段数据,管道传输的数据是无格式的流且大小受限。

对于匿名管道,它的通信范围是存在父子关系的进程,因为管道没有实体,也就是没有管道文件,只能通过fork来复制父进程fd文件描述符,来达到通信的目的;

对于命名管道,它可以在不相关的进程间也能相互通信,因为命名管道,提前创建了一个类型为管道的设备文件,在进程里只要使用这个设备文件,就可以相互通信;

不管是匿名管道,还是命名管道,进程写入的数据都是缓存在内核中,另一个进程读取数据时自然也是从内核中获取,同时通信数据都遵循先进先出原则,不支持lseek之类的文件定位操作。

2.消息队列 消息队列是保存在内核中的消息链表,在发送数据时,会分成一个一个独立的数据单元,也就是消息体,消息体是用户自定义的数据类型,消息的发送方和接收方要约定好消息体的数据类型,所以每个消息体都是固定大小的存储块,不像管道是无格式的字节流数据,如果进程从消息队列读取了消息体,内核就会把这个消息体删除。

A进程要给B进程发送消息,A进程把数据放在对应的消息队列后就可以正常返回了,B进程需要的时候再去读取数据就可以了。同理,B进程要给A进程发送消息也是如此。

缺点:一是通信不及时,二是附件也有大小限制,

消息队列不适合比较大数据的传输,因为在内核中每个消息体都有⼀个最大长度的限制,同时所有队列所包含的全部消息体的总长度也是有上限。在 Linux 内核中,会有两个宏定义 MSGMAX 和 MSGMNB , 它们以字节为单位,分别定义了⼀条消息的最大长度和⼀个队列的最大长度。

消息队列通信过程中,存在⽤户态与内核态之间的数据拷贝开销,因为进程写入数据到内核中的消息队列时,会发生从用户态拷贝数据到内核态的过程,同理另⼀进程读取内核中的消息数据时,会发生从内核态拷贝数据到用户态的过程。

3.共享内存 消息队列的读取和写入过程,会产生用户态和内核态之间的数据拷贝,共享内存能够解决这一问题。

共享内存的机制,就是拿出一块虚拟地址空间来,映射到相同的物理内存中。

这样这个进程写入的东西,另外一个进程马上就能看到了,就不需要拷贝来拷贝去,大大提高了进程间通信的速度。

4.信号量 为了防止多进程竞争共享资源,而造成的数据错乱,所以需要保护机制,使得共享的资源,在任意时刻都能被一个进程访问,信号量就实现了这一保护机制。

信号量其实是一个整型的计数器,主要用于实现进程间的互斥和同步,而不是用于缓存进程间通信的数据。

控制信号量的方式有两种原子操作:

一个是P操作,这个操作会将信号量-1,如果相减后<0,则表示资源已被占用,进程需阻塞等待;相减后如果信号量≥0,则表明还有资源可使用,进程可正常继续执行;

另一个是V操作,这个操作会把信号量+1,相加后如果信号量≤0,则表明当前有阻塞中的进程,于是会将该进程唤醒运行;相加后如果信号量>0,则表明当前没有阻塞中的进程;

信号量用来进行多进程有执行顺序的场景,来实现同步。--同步信号量

5.信号 Ctrl+C 产⽣ SIGINT 信号,终止进程;

Ctrl+Z 产⽣ SIGTSTP 信号,停止进程,还未结束;

信号是进程间通信机制中唯一的异步通信机制,因为可以在任何时候发送信号给某一进程,一旦有信号产生,就有以下几种,用户进程对信号的处理方式:

1.执行默认操作:Linux对每种信号都规定了默认操作,比如SIGTERM信号就是终止进程的意思;

2.捕捉信号:我们可以微信号定义一个信号处理函数,当信号发生时,我们就执行相应的信号处理函数;

3.忽略信号:当我们不希望处理某些信号的时候,就可以忽略该信号,不做任何处理,有两个信号使用用进程无法捕捉和忽略的,即SIGKILL和SEGSTOP,他们用于在任何时候中断或结束某一进程。


©著作权归作者所有:来自51CTO博客作者mb65950ac695995的原创作品,请联系作者获取转载授权,否则将追究法律责任 嵌入式硬件八股文7 https://blog.51cto.com/u_16492406/13111435