欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 文旅 > 游戏 > 【Linux课程学习】第十九弹---深入理解进程间通信---匿名管道,命名管道,多匿名管道的BUG

【Linux课程学习】第十九弹---深入理解进程间通信---匿名管道,命名管道,多匿名管道的BUG

2025/9/15 1:51:49 来源:https://blog.csdn.net/djdjiejsn/article/details/144323568  浏览:    关键词:【Linux课程学习】第十九弹---深入理解进程间通信---匿名管道,命名管道,多匿名管道的BUG

🎁个人主页:我们的五年

🔍系列专栏:Linux课程学习 

🌷追光的人,终会万丈光芒

🎉欢迎大家点赞👍评论📝收藏⭐文章

Linux学习笔记:

 https://blog.csdn.net/djdjiejsn/category_12669243.html

前言:

从本篇开始,就要来谈谈进程间通信。方式有很多,设计的模式也不一样。根据后面网络的编程的需求,某些进程间通信可能用的更广。文章会从进程间通信的介绍,匿名管道,命名管道,system V 共享内存讲解,system V可能会放在下面文章讲解。

目录

一.进程间通信介绍

1.1进程间通信的目的:

1.2进程间通信的发展:

1.3进程间通信的分类:

二.匿名管道

2.1管道的介绍:

2.2匿名管道创建:

2.2.1函数介绍:

2.2.2函数解读:

2.3匿名管道实现通信实现:

2.3.1关闭相应的端口:

2.3.2写端关闭,读端如何反应?

2.3.3读端关闭,写端如何反应? 

2.3.4其他情况:

三.命名管道

3.1命名管道的介绍:

它和匿名管道的区别主要体现在:

3.2如何创建管道?

3.2.1在命令行中创建一个命名管道:

3.2.2通过函数创建:

 四.关于Makefile文件的编写:


一.进程间通信介绍

我们知道,进程是具有独立性的,那么我们想要让一个进程从另外一个进程得到信息,我们要怎么做呢?这就有了进程间通信。

进程间通信的本质是让不同的进程看到同一份资源

这块内存的特点:由操作系统(OS)创建,是内存级空间(没必要到达磁盘这一级去)。

1.1进程间通信的目的:

🥬1.数据传输一个进程需要把它的数据发生给另外一个进程。

🥬2.资源共享:多个进程直接共享同样的资源

🥬3.通知事件:一个进程向另一个进程或者一组进程发生消息,通知它们发生某种事件。

🥬4.进程控制:有些进程希望完全控制另一个进程的执行,此时控制进程希望能够拦截另一个进程的所有陷入和异常,并且能及时知道它的状态信息。

上面所有的目的都是因为进程间通信,可以让不同进程间传递数据

1.2进程间通信的发展:

管道
System V进程间通信
POXIS进程间通信

1.3进程间通信的分类:

下面是本地通信的分类,除了本地通信,还有网络通信

管道:匿名管道(pipe),命名管道(FIFO)。

System V:System 消息队列,System V共享内存,System V 信号量。

POSXI IPC:消息队列,共享内存,信号量,互斥量,条件变量,读写锁。


二.匿名管道

2.1管道的介绍:

管道式一种古老的通信方式,它设计不要专门去设计一套通信,而是用文件进行修改就能通信的方式。

我们把一个进程连接到另一个进程的数据流称为管道

管道的特性是面向字节流的。单向的

在创建多管道的时候,会有BUG。父子进程能进程同样的文件描述符,但在创建躲管道的时候,这也是他缺点。

匿名管道也是只能用于有亲缘关系之间的进程进行通信。因为他们要进行继承父进程的文件描述符,才能让他们看到同样的空间。

在Ubuntu系统中,管道的大小一般是64KB。

2.2匿名管道创建:

2.2.1函数介绍:

头文件:
#include <unistd.h>

函数原型:

int pipe(int pipefd[2]);

2.2.2函数解读:

🎒功能:创建一无名管道。

🎒参数:传入的fd表示的int数组类型的指针。如果成功,fd[0]中表示读端的文件描述符,fd[1]表示的写端的文件表述符。

🎒返回值:成功返回0,错误返回错误代码。

2.3匿名管道实现通信实现:

下面的代码实现的是,打开一个匿名管道。然后返回的是文件描述符。通过创建子进程,子进程继承父进程的文件描述符。这样就让父子进程看到同一个文件。因为要保证单向性,最好就是把没有用的端关闭。这样尽量保证安全性。

2.3.1关闭相应的端口:

比如父进程只进行读取数据,那么他就把写入端关闭。子进程进行写入,那么子进程就把读端关闭。

2.3.2写端关闭,读端如何反应?

另外如果管道没有东西,读端就阻塞住,等待写端写入数据。如果写端关闭,那么读端把管道里的数据读完以后,就会读到空。返回的就是0。这样就可以判断可以关闭读端了。

2.3.3读端关闭,写端如何反应? 

读端关闭,写端进程会发生错误,管道里的数据也会被处理。匿名管道读端关闭后,写端进程继续写入数据会面临错误返回或者收到终止信号等情况,并且管道内剩余未读的数据也会被相应处理掉。

OS通过信号杀死进程。通过kill -13杀死进程。IPC!!!

2.3.4其他情况:

管道为空&&管道正常,那么read阻塞

管道为满&&管道正常,那么write阻塞

写入的数据量不大于PIPE-BUF时,Linux保证写入的原子性

写入的数据大于PIPE-BUF时,Linux保证写入的原子性

#include <iostream>
#include <unistd.h>// child send message to father
int main()
{int fd[2];int n = pipe(fd);// 匿名管道创建失败,成功返回0,失败返回非0if (n != 0){std::cerr << "pipe error!\n"<< std::endl;return 1;}// 创建子进程,并且父子进程关闭对应的文件fd。int id = fork();if (id < 0){std::cerr << "fork error!\n"<< std::endl;}// child  关闭读端if (id == 0){::close(fd[0]);int num = 0;while (1){std::string s;std::cin >> s;num += ::write(fd[1], s.c_str(), s.size()-1);std::cout << "num:" << num << std::endl;}}// father  关闭写端else{::close(fd[1]);while (1){char buf[1024];int end = ::read(fd[0], buf, sizeof(buf));if (end > 0){buf[end] = '\0';}else if (end == 0){close(fd[0]);break;}printf("father:%s\n\n", buf);}}return 0;
}

 2.4多个匿名管道产生的BUG

在我们pipe创建多个管道的时候,在第一次把一个管道创建好以后,我们会进行把某个进程的读端打开,某个进程的写端关闭。然后再去创建下一个匿名管道。

这个时候我们fork出来的子进程,还会继承父进程的一系列的文件描述符,其中就包括了指向上一个匿名管道的读端或者写端。所以我们要进行一一的关闭。

创建一个管道,对应要关一次,创建两个匿名管道,就要关两次了,以此类推。


三.命名管道

3.1命名管道的介绍:

命名管道不再受血液的限制,可以让任意两个进程进行通信。命名管道是一种特殊的管道。命名管道会有一个真实的文件在指定文件夹中。

命名管道其实就是一个文件,只是这个文件被OS经过特殊的处理,只占用内核的空间,不会去进行磁盘级的操作。

它和匿名管道的区别主要体现在:

1.匿名有pipe函数创建并且打开。

2.命名管道由mkfifo创建,由open打开。

除了这些打开方式的区别以外,匿名管道和命令管道的用法基本相同

3.2如何创建管道?

3.2.1在命令行中创建一个命名管道:

在命令行中输入下面的命令:

mkfifo share

 mkfifo表示创建一个命名管道,后面的是命名管道的名称。

3.2.2通过函数创建:

头文件:

#include <sys/types.h>

 #include <sys/stat.h>

函数原型:
int mkfifo(const char *pathname, mode_t mode);

函数解读:

pathname表示的是创建命名管道的路径,可以是./fifofile这样的路径,然后就会在当前路径创建命名管道。命名管道其实就是一个文件,只是这个文件被OS经过特殊的处理,只占用内核的空间,不会去进行磁盘级的操作。

但命令管道被创建,先打开的是写,而读端还没启动,那么就会阻塞住。不然直接就是写端有,读端没有,就会被OS杀死。所以在这一点,还是进行了特殊处理的。


 四.关于Makefile文件的编写:

BIN表示的是目标程序,SRC是源文件,OBJ是经过预处理,编译和汇编以后的文件。

CC表示所用的编译器,FLAGSLDFLAGS是选项。

test是查看所有的.o和.cc。

BIN=pipe
SRC=$(wildcard *.cc)
OBJ=$(SRC:.cc=.o)CC=g++
FLAGS=-c -Wall -std=c++11 
LDFLAGS=-o$(BIN):$(OBJ)$(CC) $(LDFLAGS) $@ $^%.o:%.cc$(CC) $(FLAGS) $<.PHONY:clean
clean: rm -rf $(BIN) $(OBJ).PHONY:test
test:@echo $(SRC)@echo $(OBJ)

文章已经接近尾声,后续会进行更新System V共享内存,可以关注一下新的博客。如果看懂文章欢迎到下面进行投票。你的支持是我前进的最大动力。

🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷🌷

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词