我们先来说说管道时做什么用的?
所谓管道,就是指能够连续一个写进程和一个读进程,并允许它们以生产者-消费者的身份进行通信的一种共享文件,又称为pipe文件。由写进程在管道的写入段(0端)将数据写入管道,而读进程则是在管道的读出端(1端)将数据读出。
管道分为匿名管道和有名管道。
在说匿名管道之前,我们先来解决一下管道的一些小的问题。
一、pipe文件的建立
分配磁盘和内存索引结点、为读进程分配文件表项、为写进程分配文件表项、分配用户文件描述符。
二、读/写进程互斥
内核为地址设置一个读指针和一个写指针,按先进先出顺序读、写。为使读、写进程互斥地访问pipe文件,需使各进程互斥地访问pipe文件索引结点中的直接地址项。因此,每次进程在访问pipe文件前,都需检查该索引文件是否已被上锁。若是,进程便睡眠等待,否则,将其上锁,进行读/写。操作结束后解锁,并唤醒因该索引结点上锁而睡眠的进程。
三、一些管道会涉及到的函数先来了解一下。
1、pipe()
建立一无名管道。
系统调用格式:pipe(filedes)
参数定义:intpipe(filedes);int filedes[2];
其中,filedes[1]是写入端,filedes[0]是读出端。
2、read()
系统调用格式
read(int fd[0],char* buf,unsigned nbyte)
功能:从fd所指示的文件中读出nbyte个字节的数据,并将它们送至由指针buf所指示的缓冲区中。如该文件被加锁,等待,直到锁打开为止。
参数:fd[0]表示以读的形式进入,buf表示将读到的内容写在buf中,nbyte表示需要读取的字节数。
3、write()
系统调用格式
write(int fd[1],char* buf,unsigned nbyte)
功能:把nbyte个字节的数据,从buf所指向的缓冲区写到由fd所指向的文件中。如文件加锁,暂停写入,直至开锁。
参数:fd[1]表示以写的形式进入,buf表示将buf中的内容写入管道,nbyte表示需要写入的字节数。
参数定义同read()。
接下来,我们先来说说什么是匿名管道(无名管道)吧。
一个临时文件,利用pipe()建立起来的无名文件(无路径名),只有亲缘关系的进程之间才可以进行匿名管道的通信。
看一段代码了解一下:
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<stdlib.h>
int main()
{
int fd[2] = {0};
if(pipe(fd) == -1)
{
perror("pipe");
return 1;
}
pid_t pid = fork();
if(pid < 0)
{
perror("fork");
return 2;
}
else if(pid == 0)//child
{
close(fd[0]);
const char* msg = "father, i am child";
int i = 5;
while(i--)
{
write(fd[1],msg,strlen(msg));
sleep(1);
}
}
else//father
{
close(fd[1]);
char buf[1024];
while(1)
{
// sleep(5);
ssize_t s = read(fd[0],buf,sizeof(buf)-1);
if(s > 0)
{
buf[s] = 0;
printf("fathe: %s\n",buf);
}
else if(s == 0)
{
printf("child quit\n");
break;
}
else
{
perror("read");
break;
}
}
}
return 0;
}
我们接下来看看运行结果:
fathe: father, i am child
fathe: father, i am child
fathe: father, i am child
fathe: father, i am child
fathe: father, i am d
child quit
虽然运行结果是固定的码中可以看出
fathe: father, i am child
是一句一句出来的并不是一次性出来,最管道里没有内容了,就打
印出来了一句
child quit
最后,我们再来再来说说关于管道的四种情况(子进程写,父进程读):
1、子进程只写一次,直接跳出,父进程也只读一条。写端一直在写,突然写端关闭,读端就会一直在读,直到读到管道结尾类似于文件结尾,再读就到了0值。
2、子进程不写也不关闭读端,父进程就一直在等,直到等到文件结束。
3、写端一直在写,读端一直不读,写满了,写端就不写了,等读端读。(二者访问具有一致性)。当读端读时,管道是以字节流的形式往出读,并不是以你写的方式往出读,可能会一次性读出来一大片。
4、写进程一直在写,读进程不光不读还直接关掉。当读端关闭时,写端就会被立刻终止,被操作系统终止,属于,代码没有跑完退出了(进程异常)。由于,父进程是读进程,子进程是写进程,所以,父进程就可以得到子进程终止信息。