网站建设高端培训学校,外国网站开发,青岛谷歌推广,室内设计培训内容Linux进程间通信#xff1a;匿名管道 命名管道 一、进程间通信目的二、什么是管道三、匿名管道创建3.1 系统调用原型3.2 匿名管道创建 四、内核创建匿名管道过程五、匿名管道性质5.1 匿名管道的4种特殊情况5.2 匿名管道的5种特性5.3 测试源代码 六、命名管道6.1 创建命名… Linux进程间通信匿名管道 命名管道 一、进程间通信目的二、什么是管道三、匿名管道创建3.1 系统调用原型3.2 匿名管道创建 四、内核创建匿名管道过程五、匿名管道性质5.1 匿名管道的4种特殊情况5.2 匿名管道的5种特性5.3 测试源代码 六、命名管道6.1 创建命名管道1. 命名行创建 6.2 代码中创建 七、命名管道性质7.1 匿名管道与命名管道的区别7.2 命名管道的打开规则 八、进程池制作基于匿名管道和命名管道两个版本 一、进程间通信目的 进程间通信的本质是不同进程看到同一份资源。该资源一般由操作系统提供比如缓冲区 进程间通信目的主要有
数据传输一个进程需要将它的数据发送给另一个进程。资源共享多个进程之间共享同样的资源。通知事件一个进程需要向另一个或一组进程发送消息通知它它们发生了某种事件如进程终止时要通知父进程。进程控制有些进程希望完全控制另一个进程的执行如Debug进程此时控制进程希望能够拦截另一个进程的所有陷入和异常并能够及时知道它的状态改变。
二、什么是管道 管道最早是UNIX中的一种进程通信方式。我们把一个进程到另一个进程的一个数据流称为管道管道文件时一个纯内存级文件不需要想磁盘刷新。 三、匿名管道创建
3.1 系统调用原型 系统中提供了系统调用接口pipe()用于创建匿名管道。
#include unistd.hint pipe(int pipefd[2]);pipefd为输出型参数pipefd[1]为写端pipefd[0]为读端创建成功返回0否则返回-1.
此时创建结果如下
3.2 匿名管道创建 四、内核创建匿名管道过程 在一个进程中我们分别通过r和w两种方式打开同一个文件此时进程文件描述符表中存在两个文件描述符fd指向两个文件结构体对象file。但两个结构体对象指向同一个文件即相同的inode、同一个方法集、同一块缓冲区 此时我们通过fork()创建出子进程子进程继承了父进程的file结构体对象新创建的文件属于文件管理不属于进程管理所以不需要给子进程也拷贝一份 此时我们将父进程的写段关闭子进程的读端关闭即子写父读。此时我们就形成了一个匿名管道父子两个进程都看到同一份资源文件缓冲区数据从子进程写入到文件中父进程从文件中读取数据形成数据流
上述这种文件和普通文件不同不会向磁盘刷新数据。并且文件的缓冲区是父进程和子进程所能看到的同一份资源而向这种文件我们称之为管道。该管道没有名字所以被称为匿名管道
五、匿名管道性质
5.1 匿名管道的4种特殊情况
正常情况下如果管道数据为空此时读端必读等待直到有数据为止写段向管道中写入数据正常情况下如果管道数据写满此时写端会停止写入直到有空间为止如果写端关闭读端一直读取读端读取到的read返回值为0如果读端关闭写端一直写入此时操作系统会通过向写端发送13号信号直接杀掉写端进程。
5.2 匿名管道的5种特性
匿名管道仅用于具有血缘关系的进程间进行相互通信常用于父子进程间。匿名管道默认会给读写端提供同步机制。即管道为空读端等待写端写入管道满了写端等待读端读取。匿名管道面向字节流即通过read读取指定大小数据数据过小不会读取管道的生命周期随进程。当进程全部退出时此时管道的引用计数减为0操作系统会将管道文件释放。匿名管道具有单向通信特点是半双工通信的一种特殊情况数据只能向一个方向流动。匿名管道具有原子性。当要写入的数据量不大于PIPE_BUF时linux将保证写入的原子性。即当管道中的数据量小于PIPE_BUF和指定大小时此时读端会等待子进程写入。当要写入的数据量大于PIPE_BUF时linux将不再保证写入的原子性。
5.3 测试源代码
#include iostream
#include cassert
#include cstdlib
#include cstring
#include sys/types.h
#include sys/wait.h
#include unistd.husing namespace std;#define MAX 1024int main()
{//1. 创建管道int pipefd[2];int n pipe(pipefd);assert(n 0);(void)n;// 2. 创建子进程pid_t id fork();if(id 0){perror(fork);return 1;}//3. 关闭不需要的fd, 形成匿名管道int cnt 5;if(id 0)//child{close(pipefd[0]);//子进程关闭读端while(true){char message[MAX];// snprintf把原本打印到显示器的信息打印到指定文件中snprintf(message, sizeof(message), I am child, pid: %d, cnt: %d, getpid(), cnt--);write(pipefd[1], message, strlen(message));//sleep(1);if(cnt 0) break;cout write---- endl;}cout child quit endl;exit(0);}//parentclose(pipefd[1]);//父进程关闭写端while(true){// sleep(1);char buffer[MAX];// read 把pipefd[0]对于文件中最大517个字节写入buffer缓冲区中ssize_t n read(pipefd[0], buffer, 517);if(n 0){cout child quit, me too endl;break;}else if(n 0){buffer[MAX - 1] 0;cout chils say: buffer endl;}break;}cout parent quit endl;close(pipefd[0]);//回收子进程int status;pid_t rid waitpid(id, status, 0);if(rid id){cout wait child: id success exit singal (status0x7f) endl;}return 0;
}六、命名管道 匿名管道中能在具有血缘关系的进程间进行相互通信。那两个毫无关系的独立进程该如何通信了 在不相关的进程之间交换数据可以使用FIFO文件来做这项工作的管道称为命名管道。命名管道是一种特殊类型的文件。
6.1 创建命名管道
1. 命名行创建 我们可以在命令行上创建命名管道创建方式如下
mkfifo xxx【实例】
6.2 代码中创建 我们也可以在代码中使用系统调用接口创建函数原型如下
#include sys/types.h
#include sys/stat.hint mkfifo(const char *filename,mode_t mode);// mode为带创建管道权限七、命名管道性质
7.1 匿名管道与命名管道的区别
匿名管道由pipe函数创建并打开命名管道由mkfifo函数创建打开用open。FIFO命名管道与pipe匿名管道之间唯一的区别在它们创建与打开的方式不同一但这些工作完 成之后它们具有相同的语义
7.2 命名管道的打开规则
如果当前打开操作是为读而打开FIFO时
O_NONBLOCK disable阻塞直到有相应进程为写而打开该FIFO。O_NONBLOCK enable立刻返回成功
如果当前打开操作是为写而打开FIFO时
O_NONBLOCK disable阻塞直到有相应进程为读而打开该FIFO。O_NONBLOCK enable立刻返回失败错误码为ENXIO。
八、进程池制作基于匿名管道和命名管道两个版本
Linux进程池制作基于匿名管道和命名管道两个版本