详解IPC中的管道和共享内存

本文详细介绍了管道(包括匿名管道和命名管道)的工作原理、特性以及读写规则,强调了其在进程间通信中的应用。同时,讨论了共享内存作为最快IPC形式的原因和实现方式。此外,还提及了消息队列、信号量等其他IPC机制,提醒读者在使用后需要注意资源的清理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

管道

分类:命名管道和匿名管道

  • 命名管道:可以用于本机上的任意进程间通信
  • 匿名管道:只适用于拥有亲缘关系的进程间通信

本质:是内核中开辟的一块缓冲区

特性:

  • 读写特性:当一个进程读或者写时,其他进程不能读或者写
  • 自带同步与互斥
  • 半双工通信:数据只能向一段发送数据,若要双方通信,则要使用两个管道
  • 提供字节流服务
  • 生命周期随进程

匿名管道

原型

int pipe(int fd[2]);

fd:文件描述符数组,其中fd[0]表示读端,fd[1]表示写端

成功返回0,失败返回错误代码

//从键盘读取数据,写入管道,读取管道,写到屏幕
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main( void )
{
    int fds[2];
    char buf[100];
    int len;
    if ( pipe(fds) == -1 )
        perror("make pipe"),exit(1);
    // read from stdin
    while ( fgets(buf, 100, stdin) ) {
        len = strlen(buf);
        // write into pipe
        if ( write(fds[1], buf, len) != len ) {
            perror("write to pipe");
            break;
       }
        memset(buf, 0x00, sizeof(buf));
        
        // read from pipe
        if ( (len=read(fds[0], buf, 100)) == -1 ) {
            perror("read from pipe");
            break;
       }
        // write to stdout
        if ( write(1, buf, len) != len ) {
            perror("write to stdout");
            break;
       }
   }
}

 用fork来共享管道原理

 

站在文件描述符角度深度理解管道

站在文件描述符角度看待这个问题之前,我们要理解一件事情,文件描述符的分配规则是最小未使用,0是标准输入,对应键盘,1是标准输出,对应显示器,2是标准错误,对应显示器,所以假设这里的进程未使用其他文件操作符,所以按照操作系统的分配规则,会给fd[0]分配3,fd[1]分配4

站在内核角度,看待管道本质

所以说,内核看待管道也是如同文件一样,管道的使用同文件一致,这也就符合Linux下一切皆文件的思想

 

管道的读写特性

当没有数据可读时

  • O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
  • O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。

当管道满的时候

  • O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
  • O_NONBLOCK enable:调用返回-1,errno值为EAGAIN

如果所有管道写端对应的文件描述符被关闭,则read返回0

如果所有管道读端对应的文件描述符被关闭,则write操作会产生信号SIGPIPE,进而可能导致write进程

退出

当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

匿名管道特点

只能用于具有共同祖先的进程(据有亲缘关系的进程)之间进行通信,通常,一个管道由一个进程创建,然后由这个管道fork一个子进程,此后父子进程就可以应用该管道

管道提供流式服务

一般而言,进程退出,管道销毁,生命周期随进程

一般而言,内核会对管道操作同步和互斥

管道是半双工的,一般只能有一个进程向另一个进程发送消息,如果要两个进程互发消息,则需要创建两个管道

命名管道

匿名管道应用的一个限制就是只能在具有亲缘间关系的进程间通信,如果我们想要在不同进程间进行通信,就需要借助FIFO文件,它也被叫做命名管道,可以在命令行创建,也可以在程序内部创建,在命令行用mkfifo name创建,在程序内部借助函数

int mkfifo(const char* name ,mode_t mode);创建

匿名管道和命名管道的区别

  • 匿名管道由pipe函数创建并打开
  • 命名管道由mkfifo创建,用open打开
  • FIFO(命名管道)和pipe(匿名管道)除了创建和打开的操作不同之外,之后的语义操作完全相同

 

共享内存

共享内存是IPC中最快的形式,这是因为共享内存是内存上的一块空间,少了两次用户态和内核之间的数据拷贝,所以是最快的

本质:在内存空间开辟一片空间,然后将这块地址映射到各个进程的进程空间中

消息队列

消息队列提供了一个从一个进程向另一个进程发送一块数据的方法

每个数据块都被认为是有一个类型,接收者进程接收的数据块可以由不同的类型值

信号量

信号量主要用于同步与互斥

由于各进程要求共享资源,而且有些资源需要互斥使用,因此各进程间竞争使用这些资源,进程的这种

关系为进程的互斥

系统中某些资源一次只允许一个进程使用,称这样的资源为临界资源或互斥资源。

在进程中涉及到互斥资源的程序段叫临界区

注意

IPC是系统资源,所以我们在使用他们之后,一定要记得删除掉,否则不会自动清除,除非重启,所以system V IPC资源的生命周期随内核

那么system V IPC有哪些呢?

消息队列,共享内存,信号量

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值