管道(pipe):用于亲缘关系进程间(如父子进程,兄弟进程)的通信
一个进程写管道:写入字节数小于PIPE_BUF是原子操作,写操作在管道缓冲区没有及时读走时发生阻塞。
一个进程读管道:读操作在管道缓冲区没有数据时发生阻塞。
主要函数:
int pipe(int filedes[2]);
代码实例创建了父子进程,父进程写管道,子进程读管道。
代码验证了写阻塞:子进程读一次管道就休眠1秒,父进程一次写操作后将阻塞,直到子进程取走数据。
代码验证了读阻塞:父进程的写一次管道后休眠1秒,子进程一次读操作后将阻塞,直到父进程再次写数据。
如果管道内的实际数据比请求读的要少,读不阻塞。
但是无法验证写入字节数大于PIPE_BUF不是原子操作,我想不出一个方法来验证它。
附代码
#include < unistd.h >
#include < sys / types.h >
#include < errno.h >
#include < stdlib.h >
main()
{
int pipe_fd[2];
pid_t pid;
int len = 4096*2;
char r_buf[len];
char w_buf[len];
char* p_wbuf;
int r_num;
int w_num;
int cmd;
memset(r_buf,0,sizeof(r_buf));
memset(w_buf,0,sizeof(r_buf));
p_wbuf=w_buf;
if(pipe(pipe_fd)<0)
{
printf("pipe create error ");
return -1;
}
if((pid=fork())==0)
{
close(pipe_fd[1]);
while(1)
{
r_num=read(pipe_fd[0],r_buf,sizeof(r_buf));
if(r_num==0)
break;
printf( "读字节数:%d ",r_num);
//sleep(1);//验证写阻塞
}
close(pipe_fd[0]);
printf( "子进程退出... ");
}
else if(pid>0)
{
close(pipe_fd[0]);//关闭读
//sleep(5);
while(1)
{
//w_num = write(pipe_fd[1],w_buf,sizeof(w_buf));
w_num = write(pipe_fd[1],w_buf,111);
if(w_num!=-1)
printf( "写字节数:%d ",w_num);
else
printf( "error ");
sleep(1);//验证读阻塞
}
close(pipe_fd[1]);//关闭写
printf( "父进程退出... ");
}
}
有名管道(FIFO):与管道不同,可以在没有亲缘关系的多个进程间通信。
创建完FIFO,读或写FIFO的进程首先要有打开FIFO的操作:
读FIFO的进程以阻塞方式读打开,如果没有其它进程写则打开操作阻塞;
写FIFO的进程以阻塞方式写打开,没有其它进程读则打开操作阻塞。
某进程以阻塞方式读FIFO,如果FIFO没有数据或是有数据但其它进程在读,则发生阻塞。
某进程以阻塞方式写FIFO,与写管道是一样的,写入字节数小于PIPE_BUF是原子操作,
写操作在管道缓冲区没有及时读走数据时发生阻塞。
主要函数:
int mkfifo (const char *pathname, mode_t mode);
附代码
#include < unistd.h >
#include < sys / types.h >
#include < errno.h >
#include < stdlib.h >
#include < stdio.h >
#include < sys / stat.h >
#include < fcntl.h >
#define FIFO " fifo "
main()
{
pid_t pid;
int fd_r,fd_w;
int num_r,num_w;
int len = 40;
char buf_r[len];
char buf_w[len];
//也可以在shell下用mkfifo创建fifo
if((mkfifo(FIFO,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))
{
printf("create fifo fail! ");
return;
}
if((pid=fork())==0)
{
sleep(1);
printf("进程(%d):准备打开fifo ",getpid());
fd_r = open(FIFO,O_RDONLY,0);
if(fd_r==-1)//以阻塞方式读打开,没有其它进程写则打开操作阻塞
{
printf("进程(%d):打开fifo失败... ",getpid());
return;
};
printf("进程(%d):打开fifo成功. ",getpid());
while(1)
{
num_r = read(fd_r,buf_r,sizeof(buf_r));
printf( "读字节数:%d ",num_r);
sleep(1);
//这里将验证写阻塞,写进程不休眠,很快就把管道写满,再写的时候就阻塞了
}
}
else if(pid>0)
{
printf("进程(%d):准备打开fifo ",getpid());
//if(open(FIFO,O_WRONLY|O_NONBLOCK,0)==-1)
fd_w = open(FIFO,O_WRONLY,0);
if(fd_w ==-1)//以阻塞方式写打开,没有其它进程读则打开操作阻塞
{
printf("进程(%d):打开fifo失败... ",getpid());
return;
}
printf("进程(%d):打开fifo成功. ",getpid());
while(1)
{
num_w = write(fd_w,buf_w,sizeof(buf_w));
printf( "写字节数:%d ",num_w);
}
}
}