Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >【进程间通信】IPC、管道pipe、命名管道FIFO

【进程间通信】IPC、管道pipe、命名管道FIFO

作者头像
mindtechnist
发布于 2024-08-08 09:09:28
发布于 2024-08-08 09:09:28
27500
代码可运行
举报
文章被收录于专栏:机器和智能机器和智能
运行总次数:0
代码可运行

一、什么是IPC

Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问,要交换数据必须通过内核,在内核中开辟一块缓冲区,进程1把数据从用户空间拷到内核缓冲区,进程2再从内核缓冲区把数据读走,内核提供的这种机制称为进程间通信(IPC,InterProcess Communication)。

在前面我们分析过进程的虚拟地址空间结构图,实际上进程的0-3G用户区是相对独立,进程之间要想通信,是通过内核提供的一块缓冲区实现的,而IPC就是进程间通过内核提供的缓冲区进行数据交换的机制。

在进程间完成数据传递需要借助操作系统提供特殊的方法,比如:文件、管道、信号、共享内存、消息队列、套接字、命名管道等。随着计算机的发展,一些方法由于自身设计缺陷被淘汰或者弃用。现今常用的进程间通信方式有:

  • 管道 (使用最简单)
    • pipe:管道(无名),只支持有血缘关系的进程通信(fork创建的)。
    • fifo:有名管道,无血缘关系的进程间也可通信。
  • mmap,文件映射共享IO,速度最快,因为它实际上是在内存中开辟一块缓冲区,然后把文件映射到这块缓冲区中,这样直接操作内存就可以了。
  • 本地socket,即本地套接字 ,是最稳定通信方式。
  • 信号 ,开销最小,携带信息量最小。
  • 共享内存
  • 消息队列

下面介绍最常用的pipe、fifo、mmap。

二、pipe管道

1. 什么是管道

管道是一种最基本的IPC机制,作用于有血缘关系的进程之间,完成数据传递。调用pipe()系统函数就可以创建一个管道。管道具有下面的特点:

  • 管道的本质是一个伪文件,实际上就是内核缓冲区。
  • 由两个文件描述符引用,一个表示读端,一个表示写端。
  • 规定数据从管道的写端流入管道,从读端流出。

管道的实现原理是这样的,实际上管道是内核使用环形队列机制,借助内核缓冲区(4K)来实现的。管道在使用时也具有一定的局限性:

  • 一是数据一旦被读走,便不在管道中存在,不可反复读取;
  • 二是由于管道采用半双工通信方式(通信方式有单工通信、半双工通信、全双工通信),因此,数据只能在一个方向上流动,有的地方也说是单工;
  • 三是只能在有公共祖先的进程间使用管道。

2. pipe()函数创建管道

2.1 函数原型

  • 包含头文件
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <unistd.h>
  • 函数原型
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
int pipe(int pipefd[2]);

#define _GNU_SOURCE
#include <unistd.h>

int pipe2(int pipefd[2], int flags);
  • 函数功能 pipe() creates a pipe, a unidirectional data channel that can be used for interprocess communication.
  • 函数参数
    • pipefd[2]:读端和写端的文件描述符
  • 函数返回值
    • On success, zero is returned.
    • On error, -1 is returned, and errno is set appropriately.

2.2 工作原理

一般来说,要在子进程创建之前使用pipe()来创建管道,这样子进程才能共享这两个文件描述符fd[1]和fd[2]。pipe()函数创建一个管道就相当于打开了一个伪文件(这个伪文件实际上是内核缓冲区,像管道文件读写数据其实是在读写内核缓冲区,因为这个缓冲区只能单向流通数据,所以形象的称为管道),所以调用成功会返回两个文件描述符给参数pipefd[2],其中fd[0]代表读端,fd[1]代表写端,就像0代表标准输入1代表标准输出一样作为一种规定。并且这两个文件描述符在使用的时候不需要open()打开,但是需要我们手动的close()关闭。

管道创建成功后,父进程同时拥有读写两端,因为子进程是对父进程的复制,所以子进程也会拥有读写两端。下面通过图示来说明进程间是如何通过管道通信的。

  • ① 父进程调用pipe()函数创建管道,并得到指向管道读端和写端的文件描述符fd[0]和fd[1]。创建出来的管道实际上是内核的一块缓冲区,我们可以像读写文件一样来操作这个缓冲区,所以也可以把他理解为一个伪文件。
  • ② 父进程调用fork()创建子进程,子进程将共享这两个指向管道读写端的文件描述符。
  • ③ 如果父进程关闭管道读端,子进程关闭管道写端,此时父进程可以向管道中写入数据,子进程将管道中的数据读出,反之同理。由于管道是利用环形队列实现的,数据从写端流入管道,从读端流出,这样就实现了进程间通信。

2.3 通过实战分析管道的特性

示例1:父子进程读写管道

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/************************************************************
  >File Name  : pipe_test.c
  >Author     : Mindtechnist
  >Company    : Mindtechnist
  >Create Time: 2022年05月21日 星期六 17时53分56秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    int fd[2];
    pipe(fd);
    pid_t pid = fork();
    
    if(pid == 0)
    {
        /*子进程向管道写*/
        /*sleep(3); read读设备的时候,默认是会阻塞等待的,写进程睡眠的时候,读进程会阻塞等待,直到读取到数据*/
        char str[] = "hello pipe...\n";
        write(fd[1], str, sizeof(str));
    }
    if(pid > 0)
    {
        char buf[15] = {0}; /*创建一个缓冲区来缓存读出的数据*/
        /*read读设备的时候,默认是会阻塞等待的*/
        int ret = read(fd[0], buf, sizeof(buf));
        if(ret > 0)
        {
            write(STDOUT_FILENO, buf, ret);
        }
    }
    return 0;
}

由于resd()函数读设备时默认阻塞等待的特性,即使写进程没有立即写,读进程也能读到数据,因为它会阻塞等待。

❀示例2:使用管道实现 ps | grep 命令

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/************************************************************
  >File Name  : mpsgrep.c
  >Author     : Mindtechnist
  >Company    : Mindtechnist
  >Create Time: 2022年05月21日 星期六 18时08分56秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    int fd[2];
    pipe(fd);
    pid_t pid = fork(); /*一个进程执行ps一个进程执行grep来实现 ps | grep*/
    
    if(pid == 0) /*子进程执行ps*/
    {/*把ps的执行结果传给grep,所以子进程写,父进程读*/
        /*首先把ps命令的执行结果重定向到管道的写端(默认将执行结果输出到stdout)*/
        dup2(fd[1], STDOUT_FILENO);
        /*拉起ps进程*/
        execlp("ps", "ps", "aux", NULL);
    }
    
    if(pid > 0) /*父进程执行grep*/
    {
        /*把grep读取重定向到fd[0],因为默认grep是在stdin获取输入的*/
        /*如果在shell命令行使用grep,模式是在标准输入中匹配*/
        dup2(fd[0], STDIN_FILENO);
        /*拉起grep进程*/
        execlp("grep", "grep", argv[1], NULL);
    }
    
    return 0;
}

上面的程序执行后,可以看到输出结果,确实显示了bash相关的进程信息

我们再起一个终端,使用 ps aux 命令查看进程会发现,子进程中拉起的ps进程变成了僵尸进程,并且父进程没有退出。(实际上,如果父进程退出了,子进程就会被init进程收养并回收)

ps进程变成僵尸进程是因为,我们在父进程中并没有回收子进程,因为execlp()函数拉起一个进程后,如果执行成功,就不会再返回了,那么我们也没办法去回收这个子进程ps。但是我们知道,如果父进程终止了,子进程就会被init进程收养并回收,所以我们只要让父进程(也就是程序中的grep进程)退出,就可以解决子进程回收问题了。

下面,我们分析下父进程为什么没有退出,正常情况下,父进程执行完grep命令就应该正常退出的。实际上,这是管道的特性引起的,我们知道,pipe()创建管道后会在内核分配一个缓冲区,并返回两个文件描述符,父进程和子进程都持有读写这两个文件描述符。我们在进程间通信的时候,因为管道是单向数据流通,所以只有一个进程写一个进程读,比如上面的程序,我们让子进程写,让父进程读,但这并不代表父进程不持有写端文件描述符。问题就在这里,虽然子进程已经变成了僵尸进程,但是父进程依然持有写端文件描述符,所以父进程就会认为还存在其他进程来写入管道,于是父进程就会等待写入,而不退出。

解决方法就是,我们在进程间通信时,要保证数据单向流通,在读进程中关闭管道的写端文件描述符,在写进程中关闭管道的读端文件描述符。我们依据这个原则来改造一下上面的程序即可。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/************************************************************
  >File Name  : mpsgrep_02.c
  >Author     : Mindtechnist
  >Company    : Mindtechnist
  >Create Time: 2022年05月21日 星期六 18时08分56秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
    int fd[2];
    pipe(fd);
    pid_t pid = fork(); /*一个进程执行ps一个进程执行grep来实现 ps | grep*/
    
    if(pid == 0) /*子进程执行ps*/
    {/*把ps的执行结果传给grep,所以子进程写,父进程读*/
        /*关闭读端文件描述符,保证数据单向流通*/
        close(fd[0]);
        /*首先把ps命令的执行结果重定向到管道的写端(默认将执行结果输出到stdout)*/
        dup2(fd[1], STDOUT_FILENO);
        /*拉起ps进程*/
        execlp("ps", "ps", "aux", NULL);
    }
    
    if(pid > 0) /*父进程执行grep*/
    {
        /*关闭写端文件描述符,保证数据单向流通,防止读进程阻塞*/
        close(fd[1]);
        /*把grep读取重定向到fd[0],因为默认grep是在stdin获取输入的*/
        /*如果在shell命令行使用grep,模式是在标准输入中匹配*/
        dup2(fd[0], STDIN_FILENO);
        /*拉起grep进程*/
        execlp("grep", "grep", argv[1], NULL);
    }
    
    return 0;
}

这样,父进程就不会阻塞等待,而是直接退出,而子进程也不会产生僵尸进程。

3. 管道的读写行为

使用管道进行进程间通信的时候,假设没有设置O_NONBLOCK标志(也就是说都是阻塞I/O操作),有以下几种特殊情况

  • 如果所有指向管道写端的文件描述符都关闭了(管道写端引用计数为0),而仍然有进程从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像读到文件末尾一样。
  • 如果有指向管道写端的文件描述符没关闭(管道写端引用计数大于0),而持有管道写端的进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
  • 如果所有指向管道读端的文件描述符都关闭了(管道读端引用计数为0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。当然也可以对SIGPIPE信号实施捕捉,不终止进程。(在讲信号的时候会细说)
  • 如果有指向管道读端的文件描述符没关闭(管道读端引用计数大于0),而持有管道读端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时再次write会阻塞,直到管道中有空位置了才写入数据并返回。

其实,总的来说可以分为读管道和写管道两种的情况

  • 读管道
    • 如果管道中有数据,read返回实际读到的字节数。
    • 如果管道中无数据:
      • 如果管道写端被全部关闭,read返回0,相当于读到文件结尾。
      • 如果写端没有全部被关闭,read阻塞等待(不久的将来可能有数据递达,此时会让出cpu),如果不想让read阻塞,可以使用fcntl设置非阻塞。
  • 写管道
    • 如果管道读端全部被关闭,会产生一个信号SIGPIPE,进程异常终止(也可使用捕捉SIGPIPE信号,使进程不终止)。
    • 如果管道读端没有全部关闭
      • 如果管道已满,write阻塞,(管道实际上是内核中的一个缓冲区,它是有大小的)。
      • 如果管道未满,write将数据写入,并返回实际写入的字节数。
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/************************************************************
  >File Name  : pipe_test2.c
  >Author     : Mindtechnist
  >Company    : Mindtechnist
  >Create Time: 2022年05月21日 星期六 17时53分56秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char* argv[])
{
    int fd[2];
    pipe(fd);
    pid_t pid = fork();
    
    if(pid == 0)
    {
        sleep(3); 
        close(fd[0]); /*关闭读端*/
        char str[] = "hello pipe...\n";
        write(fd[1], str, sizeof(str));
        close(fd[1]); /*关闭写端*/
        while(1)
        {
            sleep(1);
        }
    }
    if(pid > 0)
    {
        close(fd[1]); /*关闭写端*/
        close(fd[0]); /*关闭读端*/
        char buf[15] = {0}; 
        
        int status;
        wait(&status);
        if(WIFSIGNALED(status))
        {
            printf("kill: %d\n", WTERMSIG(status));
        }
        while(1)
        {
            int ret = read(fd[0], buf, sizeof(buf));
            if(ret > 0)
            {
                write(STDOUT_FILENO, buf, ret);
            }
        }
    }
    return 0;
}

4. 管道(缓冲区)大小

使用命令查看

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
ulimit -a

管道大小是8个512byte的大小。

也可以使用函数fpathconf()查看

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
#include <unistd.h>

long fpathconf(int fd, int name); 
/*fd可以是fd[0]或fd[1],name是一个选项*/

实际上使用 ulimit -a 看到的是内核给管道的大小,但是管道的容量实际上可能要比这个值大。

5. 管道的优缺点

  • 优点:简单,相比信号,套接字实现进程间通信,简单很多。(其实要想实现父进程和子进程双向通信,可以创建两个管道)
  • 缺点:
    • 只能单向通信,双向通信需建立两个管道。
    • 只能用于有血缘关系的进程间通信(父子、兄弟等有共同祖先的进程),有名管道可解决该问题。

三、FIFO命名管道

1. 什么是FIFO

FIFO命名管道,也叫有名管道,来区分管道pipe。管道pipe只能用于有血缘关系的进程间通信,但通过FIFO可以实现不相关的进程之间交换数据。FIFO是Linux基础文件类型中的一种,但是FIFO文件在磁盘上没有数据块,仅仅用来标识内核中的一条通道。各进程可以打开这个文件进行read/write操作,实际上是在读写内核通道,这样就实现了进程间通信。

创建FIFO的方式:

  • 使用命令创建:mkfifo 管道名,可以理解为创建一个管道伪文件。
  • 使用库函数创建:mkfifo()函数,并且一旦使用mkfifo()创建了一个FIFO,就可以使用open来打开它,常见的文件I/O函数都可用于FIFO。如:close、read、write、unlink等。

实际上,创建一个FIFO命名管道的时候,内核会为FIFO(伪)文件开辟一个缓冲区,操作FIFO文件就相当于操作这个缓冲区,以此来实现进程间的通信,这种通信实际上就是文件读写的操作来实现的。(可以把FIFO理解为一个文件,一个进程向该文件写数据,另一个进程从该文件中读书数据,前提是两个进程读写的是同一个FIFO文件才能实现通信)

2. FIFO编程实战

示例:使用FIFO实现进程间通信

创建两个进程,一个进程向FIFO写数据,一个进程从FIFO读数据。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/************************************************************
  >File Name  : write_fifo.c
  >Author     : Mindtechnist
  >Company    : Mindtechnist
  >Create Time: 2022年05月21日 星期六 22时38分08秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char* argv[])
{
    if(argc < 2)
    {
        printf("not fount fifoname\n");
        return -1;
    }
    /*打开一个fifo文件*/
    int fd = open(argv[1], O_WRONLY);
    /*写FIFO文件*/
    char buf[256];
    int count = 1;
    while(1)
    {
        memset(buf, 0, sizeof(buf));
        /*循环写入*/
        sprintf(buf, "count %04d", count++);
        /*写入FIFO*/
        write(fd, buf, strlen(buf));
        sleep(1);
    }
    close(fd);
    return 0;
}
代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
/************************************************************
  >File Name  : read_fifo.c
  >Author     : Mindtechnist
  >Company    : Mindtechnist
  >Create Time: 2022年05月22日 星期日 09时54分37秒
************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <string.h>

int main(int argc, char* argv[])
{
    if(argc < 2)
    {
        printf("not found fifoname\n");
        return -1;
    }
    int fd = open(argv[1], O_RDONLY);
    char buf[256] = {0};
    int ret;
    while(1)
    {
        memset(buf, 0, sizeof(buf));
        ret = read(fd, buf, sizeof(buf));
        if(ret > 0)
        {
            printf("read buf: %s\n", buf);
        }
    }
    close(fd);
    return 0;
}

编译两个程序生成可执行文件,并使用命令mkfifo创建一个FIFO

测试的时候,我们在SecureCRT中克隆一个会话(相当于在Linux中打开两个shell终端),一个运行写进程,一个运行读进程。要注意的是,应该先运行写进程再运行读进程。

同时我们也可以打开多个进程去读写这同一个FIFO缓冲区,当多个进程去读的时候,被读进程1读走的数据就不会再被进程2读取了,比如说下面图中所示,这个进程读到的是36 38 40,而另一个进程读到的是37 39 41。(也可以开启多个写进程去写,读者可自行测试)

我们在读写FIFO的时候都使用了open()函数,使用open函数的时候有一个注意事项,使用open打开FIFO文件的时候,read端会阻塞等待write端open打开文件,直到write进程也使用open打开FIFO的时候,read进程中的open才会返回,反过来也是一样。我们可以在open函数的前后分别打印一句话来测试,只有读端写端都open了FIFO,第二个printf()语句才能打印。实际上只要有一个write和一个read打开了FIFO,就可以,不管是同一个进程还是多个进程。

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
printf("hello open...\n");
int fd = open(argv[1], O_WRONLY);
printf("bye open...\n");

附:通过一个makefile编译多个程序

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
.PHONY:all clean
CC=gcc
CFLAGS=-Wall -g
EXE=write_fifo read_fifo

all:$(EXE)

%.o:%.c
    $(CC) $(CFLAGS) -c $< -o $@

clean:
    -@rm -f *.o $(EXE)
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2024-03-02,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 机器和智能 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
Linux进程间通信--管道(pipe和fifo)
       通过管道来实现进程间的通信的方法很经典,因为多个进程共享3-4G中的内核,所以在内核中存在一个管道(缓冲区),然后进程通过连接管道的两端从而实现通信。假如说我们现在有一根管道,我们从左端放入一个小球,那么它会从右端滚出来,那么如果我们同时向两端都放入一个小球,那么就不可能实现交叉传递了,所以管道是半双工通信(即双方都可以发送信息,但是双方不能同时发送信息),因此管道的两端一端是读端,一端是写端。那么要实现两个进程的同时读写操作,就需要用两个管道。
Ch_Zaqdt
2020/03/03
3.9K0
【Linux进程#1】IPC 进程间通信(一):管道(匿名管道&命名管道)
✨ 无人扶我青云志,我自踏雪至山巅 🌏
IsLand1314
2025/06/02
1350
【Linux进程#1】IPC 进程间通信(一):管道(匿名管道&命名管道)
【Linux】IPC 进程间通信(一):管道(匿名管道&命名管道)
为了实现两个或者多个进程实现数据层面的交互,因为进程独立性的存在,导致进程通信的成本比较高
IsLand1314
2024/11/19
4350
【Linux】IPC 进程间通信(一):管道(匿名管道&命名管道)
Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)
这种双重性使得管道既具有机制的灵活性,又具有文件的可操作性。它可以在不同的进程之间建立连接,实现数据的传递和共享,同时也可以通过标准的文件操作接口进行访问和控制。
是Nero哦
2024/07/09
5750
Linux:进程间通信(一.初识进程间通信、匿名管道与命名管道、共享内存)
Linux 的进程间通信:管道
本文介绍了管道(pipe)在Linux系统中的实现方式,从三个方面进行了详细阐述:管道的原理,命名管道,以及通过匿名管道进行的进程间通信。同时,文章还探讨了管道在Linux系统中的实际应用,包括shell脚本、cron任务以及Linux中的各种守护进程等。
邹立巍
2017/07/31
8.5K3
Linux 的进程间通信:管道
进程间通信(一)/管道
有时候需要多进程协同,让每一个进程专注于自己的事,然后把结果交给另外一个进程去处理。比如使用管道,让多进程协同,简单的有:
二肥是只大懒蓝猫
2023/03/30
5290
进程间通信(一)/管道
Linux 进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
管道可用于具有亲缘关系进程间的通信,有名管道克服了管道没有名字的限制,因此,除具有管道所具有的功能外,它还允许无亲缘关系进程间的通信。
用户6543014
2020/12/21
2.6K0
Linux 进程间通信之管道(pipe)、命名管道(FIFO)与信号(Signal)
【linux学习指南】 进程间通信&&匿名管道&&理解管道的本质
在 Unix/Linux 系统中,我们可以使用 fork() 系统调用来创建子进程,并通过共享管道(pipe)进行进程间通信。下面是使用 fork() 来共享管道的原理:
学习起来吧
2024/11/18
1510
【linux学习指南】 进程间通信&&匿名管道&&理解管道的本质
进程间通信
什么是管道? 可以理解为内存中的一个缓冲区,用于将某个进程的数据流导入,由某一个进程导出,实现通信。 再通俗的说,看图:
看、未来
2020/08/26
9030
进程间通信
C++进程间通信 详解2
Linux环境下,进程地址空间相互独立,每个进程各自有不同的用户地址空间。任何一个进程的全局变量在另一个进程中都看不到,所以进程和进程之间不能相互访问。
Freedom123
2024/03/29
9830
C++进程间通信 详解2
进程通信(一)无名管道和有名管道
《王道考研复习指导》 管道通信是消息传递的一种特殊方式。所谓“管道”,是指用于连接一个读进程和一个写进程以实现它们之间通信的一个共享文件,又名pipe文件。向管道(共享文件)提供输入的发送进程(即写进程),以字符流的形式将大量的数据送入(写)管道;而接受管道输出的接受进程(即读进程),则从管道接受(读)数据。为了协调双方的通信,管道机制必须提供一下三个方面的协调能力:互斥、同步和确定对方存在。 下面以linux的管道为例进行说明。在linux中,管道是一种频繁使用的通信机制。从本质上讲,管道也是一种文件,但它又和一般的文件有所不同,管道可以克服使用文件通信的两个问题,具体表现为: 1)限制管道的大小。实际上,管道是一个固定大小的缓冲区。在Linux中,该缓冲区的大小为4KB,使得它不像文件那样不加检验的增长。使用单个固定缓冲区也会带来问题,比如在写管道时可能变满,当这种情况发生时,随后对写管道的write()调用将默认的阻塞,等待某些数据被读取,以便腾出足够的空间供write()调用写。 2)读进程也可能工作的比写进程快。当所有当前进程数据已被读走时,管道变空。当这种情况发生时,一个随后的read()调用将默认设置为阻塞,等待某些数据被写入,这解决了read()调用返回文件结束的问题。 注意 :从管道读数据是一次性操作,数据一旦被读走,它就从管道中被抛弃,释放空间以便写更多的数据。管道只能采用半双工通信,即在某一时刻只能单向传输。要实现父子进程双方互动,需要定义两个管道。
lexingsen
2022/02/24
1.6K0
进程通信(一)无名管道和有名管道
从零开始:实现进程间管道通信的实例
匿名管道(Anonymous Pipe)是进程间通信(IPC)的一种机制,它主要用于本地父子进程之间的通信。
绝活蛋炒饭
2024/12/16
2180
从零开始:实现进程间管道通信的实例
进程间通信Linux
首先自己要用用户层缓冲区,还得把用户层缓冲区拷贝到管道里,(从键盘里输入数据到用户层缓冲区里面),然后用户层缓冲区通过系统调用(write)写到管道里,然后再通过read系统调用,被对方(读端)读取,就要从管道拷贝到读端,然后再显示到显示器上。
ljw695
2024/11/15
2880
进程间通信Linux
【Linux】基于管道进行进程间通信
进程间通信是两个或者多个进程实现数据层面的交换。但是由于进程间存在独立性,所以导致进程间通信的成本比较高。
YoungMLet
2024/03/01
2620
【Linux】基于管道进行进程间通信
深入了解linux系统—— 进程间通信之管道
本篇博客所涉及到的代码一同步到本人gitee:testfifo · 迟来的grown/linux - 码云 - 开源中国
星辰与你
2025/06/08
760
深入了解linux系统—— 进程间通信之管道
C语言第四章(进程间的通信,管道通信,pipe()函数)
本文讲解的是C语言的进程之间的通信,这里讲解的是管道通信,和相关的函数pipe().
GeekLiHua
2025/01/21
2070
Linux进程间通信之管道
1,进程间通信 (IPC ) Inter-Process Communication   比较好理解概念的就是进程间通信就是在不同进程之间传播或交换信息。 2,linux下IPC机制的分类:管道、信号、共享内存、消息队列、信号量、套接字 3,这篇主要说说管道:本质是文件,其他理论什么的网上已经有一大堆了,我就只写一点用法吧。 3.1 特点      1)管道是最古老的IPC,但目前很少使用      2)以文件做交互的媒介,管道分为有名管道和无名管道      3)历史上的管道通常是指半双工管道 3.2 管
xcywt
2018/01/11
2.7K0
Linux进程间通信之管道
【Linux】进程间通信——管道
而我们所说的不同通信种类本质就是:上面所说的资源,是OS中的哪一个模块提供的。如文件系统提供的叫管道通信;OS对应的System V模块提供的…
平凡的人1
2023/10/15
3400
【Linux】进程间通信——管道
进程间通信--管道
有时候我们需要多个进程协同的去完成某种任务,因此需要进程之间能够相互通信。但是进程之间具有独立性,要让进程之间能通信就要打破这种独立性,所以通信的代价一定是不低的。打破这种独立性就是要让两个不同的进程看到同一份资源,这个资源只能由操作系统来提供。因为如果是某个进程来提供因为独立性,这个资源就只能被提供这个资源的进程看到。
始终学不会
2023/10/17
2450
进程间通信--管道
Linux进程通信之管道解析
管道是 UNIX系统 IPC的最古老的形式,所有的UNIX系统都提供此种通信。所谓的管道,也就是内核里面的一串缓存,从管道的一段写入的数据,实际上是缓存在内核中的,令一端读取,也就是从内核中读取这段数据。对于管道传输的数据是无格式的流且大小受限。对于管道来说,也分为匿名管道和命名管道,其中命名管道也被叫做 FIFO,下面则分别阐述这两种管道。
wenzid
2021/07/20
1.4K0
Linux进程通信之管道解析
推荐阅读
相关推荐
Linux进程间通信--管道(pipe和fifo)
更多 >
LV.2
这个人很懒,什么都没有留下~
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验