【Linux】匿名管道pipe和有名管道fifo详解

创作不易,本篇文章如果帮助到了你,还请点赞 关注支持一下♡><)!!
主页专栏有更多知识,如有疑问欢迎大家指正讨论,共同进步!
Linux系列专栏:Linux基础

给大家跳段街舞感谢支持!ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ ዽ ጿ ኈ ቼ


目录

  • 一、进程间通信IPC
  • 二、匿名管道pipe
    • 使用方法
    • 匿名管道的特点
  • 三、有名管道fifo
    • 使用方法
    • 有名管道的特点

一、进程间通信IPC

进程间通信是操作系统提供的一种机制,用于多个进程之间进行数据通信,实现资源协调与共享。

IPC:Interprocess Communication 进程间通信

例如在单任务处理器中,多个进程之间就依靠着进程间通信 调度CPU,使得多个进程高效率并发执行

Linux中进程间通信的方式:

  • 管道:半双工通信方式,分为匿名管道(pipe)和有名管道(fifo),用于具有亲缘关系之间的进程通信
  • 消息队列:进程利用消息队列通过发送和接收消息进行通信
  • 信号:主要用于消息的通知和进程控制,不能传输大量数据,仅作为一种简单的通信方式
  • 内存共享映射:多个进程可以共享同一块内存,可以实现数据共享,需要同步互斥机制
  • Socket套接字:支持全双工通信,数据可以在任意时刻发送和接收,常用于网络通信

二、匿名管道pipe

匿名管道用于具有亲缘关系的进程之间的通信,无法与其他进程进行通信。

使用方法

在管道使用前需要先确定数据传输的方向,只能用于单向通信,即数据只能从一端写入,从另一端读取。

调用pipe(int fd[2])函数后,进程将会在内核层创建一个管道缓冲区(环形队列),当管道被创建成功后,将会传出两个文件描述符:fd[0]为读取,fd[1]为写入文件描述符。

由于子进程会继承父进程的文件描述符表,父进程和子进程可以分别获得一个文件描述符,父子进程间传输数据就依靠这两个文件描述符。

使用举例:

#include 
#include 
#include 
#include 
int main()
{
	pid_t pid;
	int fd[2]; //读取和写入文件描述符号
	pipe(fd);  

	pid = fork();
	if(pid > 0) //父进程
	{
		close(fd[0]);  //确定通信方向:关闭读端
		char* str = "TianXiStudio";
		write(fd[1],str,strlen(str));
		close(fd[1]);  //写入完成,关闭写入文件描述符
		wait(NULL);     //回收僵尸进程
		exit(0);
	}
	else if(pid == 0)  //子进程
	{
		close(fd[1]);  //确定通信方向:关闭写端

		char buf[1024];
		bzero(buf,sizeof(buf));

		read(fd[0],buf,sizeof(buf));  //从管道中读取数据
		printf("read:%s\n",buf);

		close(fd[0]);  //读取完成,关闭读取文件描述符
		exit(0);
	}
	else
	{
		perror("fork failed");
		exit(0);
	}
	return 0;
}

子进程从管道中读取数据:

image.png

匿名管道的特点

  • 匿名管道被亲缘关系所限制,无法与其他进程进行通信
  • 只能用于单向通信,数据只能从一个方向流动
  • 基于字节流进行通信,数据按照顺序写入和读取
  • 有名管道可以作为临时存储介质,例如:ubuntu16.04中管道缓冲区为4K大小
  • 管道的生命周期随着进程的结束而结束,管道的回收使用管道引用计数
  • 由于管道是半双工通信方式,支持异步通信,自带同步互斥
  • 当管道缓冲区为空或已满时,将会造成读取或写入阻塞
  • 使用管道通信时,需要确保及时关闭管道。读取端关闭时,写入端仍写入数据时,写入端进程将会被SIGPIPE杀死。写入端关闭时,读取端读取管道数据后返回0。

三、有名管道fifo

有名管道是一种特殊的文件类型,存在于文件系统中,但并不是用于存储数据的,而是用于进程间通信。

相比于匿名管道的亲缘间通信,有名管道可以支持非亲缘关系之间的通信

使用方法

使用命令mkfifo或函数mkfifo()来创建管道文件,两个进程间通过打开管道文件后使用read()函数读取或write()写入,进行通信。

管道文件本身不能存储,通过重定向到管道缓冲区中,对管道文件读写就会对管道缓冲区进行读写当进程不再需要使用管道时,应关闭管道文件描述符。

写入进程:

#include 
#include 
#include 
#include 

int main()
{
	int fd = open("fifo",O_WRONLY);
	char* str = "TianXiStudio";
	write(fd,str,strlen(str));
	close(fd);
	return 0;
}

读取进程:

#include 
#include 
#include 
#include 

int main()
{
	int fd = open("fifo",O_RDONLY);
	char buffer[1024*4];
	read(fd,buffer,sizeof(buffer));
	printf("read :%s\n",buffer);
	close(fd);
	return 0;
}

image.png

有名管道的特点

  • 数据在内存中进行传输,避免了不必要的磁盘I/O操作
  • 有名管道的文件存在不会随着进程的结束而消失
  • 只有读写两个进程都进行,有名管道才能打开使用,否则会阻塞等待

大家的点赞、收藏、关注将是我更新的最大动力! 欢迎留言或私信建议或问题。
大家的支持和反馈对我来说意义重大,我会继续不断努力提供有价值的内容!如果本文哪里有错误的地方还请大家多多指出(●'◡'●)

你可能感兴趣的:(【Linux】,linux,笔记,c++,学习,ubuntu)