管道(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);
}
}
}