管道用于进程间的通信,进程间通信的 公共资源叫做临界资源,访问临界资源的代码叫做临界区 。
管道文件以p开头,管道是一种最基本的IPC机制
管道又有匿名管道和命名管道之分
匿名管道:
调用pipe函数时在内核开辟一块要缓冲区(称为管道)用于通信,但是由pipe创建的管道只能用于具有亲缘关系之间的通信,因为必须要拥有一样的文件描述符表。
管道是一种最基本的 IPC机制,由pipe函数创建:
#include
#include<stdio.h>
#include <unistd.h>
int main()
{
int pipefd[2]={0};
int ret=pipe(pipefd);
if(ret==0)
{
printf("pipefd[0]: %d\n",pipefd[0]);
printf("pipefd[1]: %d\n",pipefd[1]);
}
return 0;
}
使用管道需要注意以下4种特殊情况(假设都是阻塞I/O操作,没有设置O_NONBLOCK标志):
1、如果所有指向管道写端的文件描述符都关闭了(管道写端的引用计数等于0),而仍然有进程 从管道的读端读数据,那么管道中剩余的数据都被读取后,再次read会返回0,就像 读到文件末尾一样。
//1 pipe
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int pipefd[2]={0};
int ret=pipe(pipefd);
if(ret==-1)
{
perror("pipe");
}
pid_t id=fork();
if(id==0)
{
int i=0;
const char*msg="hello bit!i am child";
close(pipefd[0]);
while(i<10)
{
write(pipefd[1],msg,strlen(msg));
sleep(1);
i++;
}
close(pipefd[1]);
}
else
{
char buf[1024]={0};
close(pipefd[1]);
int j=0;
while(j<100)
{
ssize_t s=read(pipefd[0],buf,sizeof(buf)-1);
if(s>0)
{
buf[s]=0;
printf("father: %s\n",buf);
j++;
}
else
{
printf("end!\n");
break;
}
}
}
wait(NULL);
return 0;
}
2、如果有指向管道写端的文件描述符没关闭(管道写端的引⽤用计数⼤大于0),⽽而持有管道写端的 进程也没有向管道中写数据,这时有进程从管道读端读数据,那么管道中剩余的数 据都被读取后,再次read会阻塞,直到管道中有数据可读了才读取数据并返回。
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int pipefd[2]={0};
int ret=pipe(pipefd);
if(ret==-1)
{
perror("pipe");
}
pid_t id=fork();
if(id==0)
{
int i=0;
const char*msg="hello bit!i am child";
close(pipefd[0]);
while(i<20)
{
if(i<10)
{
write(pipefd[1],msg,strlen(msg));//10次之后虽然写段没有关闭但是子进程已经不往管道中写数据了
}
sleep(1);
i++;
}
close(pipefd[1]);
}
else
{
char buf[1024];
close(pipefd[1]);
int j=0;
while(j<20)
{
ssize_t s=read(pipefd[0],buf,sizeof(buf)-1);
if(s>0)
{
buf[s]=0;
printf("father: %s\n",buf);
j++;
}
}
pid_t ret=wait(NULL);
}
return 0;
}
3、如果所有指向管道读端的文件描述符都关闭了(管道读端的引⽤用计数等于0),这时有进程向管道的写端write,那么该进程会收到信号SIGPIPE,通常会导致进程异常终止。
#include<stdio.h>
#include <unistd.h>
#include<stdlib.h>
#include<string.h>
int main()
{
int pipefd[2]={0};
int ret=pipe(pipefd);
if(ret==-1)
{
perror("pipe");
}
pid_t id=fork();
if(id==0)
{
int i=0;
const char*msg="hello bit!i am child";
close(pipefd[0]);
while(i<10)
{
write(pipefd[1],msg,strlen(msg));
sleep(1);
i++;
}
}
else
{
char buf[1024];
close(pipefd[1]);
int j=0;
while(j<3)
{
ssize_t s=read(pipefd[0],buf,sizeof(buf)-1);
if(s>0)
{
buf[s]=0;
printf("father: %s\n",buf);
j++;
}
}
close(pipefd[0]);
sleep(10);
int status=0;
pid_t ret=waitpid(id,&status,0);
if(ret>0)
{
if (WIFEXITED(status))
{
printf("exitCode: %d\n,sig is %d\n",(status>>8)&0xff,status&0xff);
}
else//如果进程不是正常退出 的
{
printf("child process quit not normal!\n");
WTERMSIG(status);
printf("exitCode: %d\nsig is %d\n",(status>>8)&0xff,status&0xff);
}
}
}return 0;
}
4、如果有指向管道读端的文件描述符没关闭(管道读端的引用计数大于0),而持有管道读 端的进程也没有从管道中读数据,这时有进程向管道写端写数据,那么在管道被写满时 再次write会阻塞,直到管道中有空位置了才写入数据并返回。
管道被写满,管道是有最大容量的。
见此文: http://blog.csdn.net/persistence_s/article/details/72779358
命名管道
匿名管道的一个不足之处是没有名字,因此,只能用于具有亲缘关系的进程间通信,在命名管道(named pipe或FIFO)提出后,该限制得到了克服。FIFO不同于管道之处在于它提供一 个路径名与之关联,以FIFO的⽂文件形式存储于⽂文件系统中。命名管道是⼀一个设备⽂文件,因 此,即使进程与创建FIFO的进程不存在亲缘关系,只要可以访问该路径,就能够通过FIFO 相互通信。值得注意的是,FIFO(first input first output)总是按照先进先出的原则⼯工作,第一 个被写入的数据将首先从管道中读出。
写端
#include<stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main()
{
umask(0);
int ret =mkfifo("./tmp",0666|S_IFIFO);
if(ret == -1)
{
printf("mkfifo error\n");
return 1;
}
int fd = open("./tmp", O_WRONLY);
if(fd < 0)
{
printf("open error\n");
}
char buf[1024]={0};
while(1){
scanf("%s", buf);
ssize_t ret = write(fd, buf, strlen(buf));
if(ret > 0){
if( strncmp(buf, "quit", 4) == 0 )
{
break;
}
}
}
close(fd); return 0;
}
读端:
#include<stdio.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include <string.h>
#include <fcntl.h>
int main()
{
int fd=open("./tmp",O_RDONLY);
if(fd<0)
{
perror("open");
return -2;
}
char buf[1024]={0};
while(1)
{
ssize_t ret=read(fd,buf,sizeof(buf)-1);
if(ret>0)
{
if(strncmp(buf,"quit",4)==0)
{
break;
}
buf[ret]=0;
printf("%s\n",buf);
}
}
close (fd);
return 0;
}