(匿名)管道的读写规则

管道读写规则:
1、当没有数据可读时

O_NONBLOCK  disable(文件状态标志)未设置非阻塞的话 : read调用阻塞,即进程暂停执行,一直等到有数据来。
O_NONBLOCK enable: 设置非阻塞模式的话,无数据可读时,read调用返回-1,errno值为EAGAIN。

总之:阻塞模式的话,如果read无数据可读就阻塞;如果非阻塞模式的话,read无数据可读,则立即返回-1.

 

  int fcntl(int fd,int cmd) cmd=F_GETFL\F_SETFL: 获取或者设置文件状态标志

 1 #include<unistd.h>
 2 #include<sys/types.h>
 3 #include<sys/stat.h>
 4 #include<fcntl.h>
 5 #include<stdlib.h>
 6 #include<stdio.h>
 7 #include<errno.h>
 8 #include<string.h>
 9 
10 #include<signal.h>
11 #define ERR_EXIT(m)\
12     do\
13     {\
14         perror(m);\
15         exit(EXIT_FAILURE);\
16     }while(0)  //宏要求一条语句
17 int main(int argc,char*argv[])
18 {
19     int pipefd[2];
20     if(pipe(pipefd)==-1)
21         ERR_EXIT("pipe error");
22     pid_t pid;
23     if((pid=fork())==-1)
24         ERR_EXIT("fork error");
25     else if(pid==0){//子进程发送数据给父进程
26         sleep(3);//未设置文件状态标识时,文件对read阻塞,前三秒没有数据可读
27         close(pipefd[0]);
28         write(pipefd[1],"hello",5);
29         close(pipefd[1]);
30         exit(EXIT_SUCCESS);
31     }
32     close(pipefd[1]);
33     char buf[10];
34     int flags=fcntl(pipefd[0],F_GETFL);//获取文件状态标识
35     fcntl(pipefd[0],F_SETFL,flags|O_NONBLOCK);//设置文件状态标识,非阻塞模式
36     if(read(pipefd[0],buf,10)==-1) ERR_EXIT("read error");//默认文件pipefd[0]阻塞
37     printf("buf=%s\n",buf);
38     close(pipefd[0]);
39     return 0;
40 }

 

2如果所有管道写端对应的文件描述符被关闭,则read返回0。

 1 #include<unistd.h>
 2 #include<sys/types.h>
 3 #include<sys/stat.h>
 4 #include<fcntl.h>
 5 #include<stdlib.h>
 6 #include<stdio.h>
 7 #include<errno.h>
 8 #include<string.h>
 9 
10 #include<signal.h>
11 #define ERR_EXIT(m)\
12     do\
13     {\
14         perror(m);\
15         exit(EXIT_FAILURE);\
16     }while(0)  //宏要求一条语句
17 int main(int argc,char*argv[])
18 {
19     int pipefd[2];
20     if(pipe(pipefd)==-1)
21         ERR_EXIT("pipe error");
22     pid_t pid;
23     if((pid=fork())==-1)
24         ERR_EXIT("fork error");
25     else if(pid==0){
26         close(pipefd[1]);//子进程写端关闭
27         exit(EXIT_SUCCESS);
28     }
29     close(pipefd[1]);//父进程写端关闭
30     sleep(1);
31     char buf[10]={0};
32     int ret=read(pipefd[0],buf,10);//读操作返回0
33     printf("ret=%d\n",ret);
34     return 0;
35 }

 

3如果所有管道读端对应的文件描述符被关闭,则write操作符产生信号SIGPIPE.

 #include<unistd.h>
 #include<sys/types.h>
 #include<sys/stat.h>
 #include<fcntl.h>
 #include<stdlib.h>
 #include<stdio.h>
 #include<errno.h>
 #include<string.h>
 
  #include<signal.h>
 #define ERR_EXIT(m)\
     do\
     {\
         perror(m);\
         exit(EXIT_FAILURE);\
     }while(0)  //宏要求一条语句
   void handler(int sig)
  {
    printf("recv a sig=%d\n",sig);
  }
  int main(int argc,char*argv[]) {
   
signal(SIGPIPE,handler); int pipefd[2]; if(pipe(pipefd)==-1) ERR_EXIT("pipe error"); pid_t pid; if((pid=fork())==-1) ERR_EXIT("fork error"); else if(pid==0){//子进程发 close(pipefd[0]); //关闭子进程读端 exit(EXIT_SUCCESS); } close(pipefd[0]); //关闭父进程读端 sleep(1); int ret= write(pipfd[1],"hello",5);
   if(ret == -1)
        printf("write error"); //捕捉信号的话会执行到这,否则默认处理函数之间结束进程 return 0; }

 

4、当管道满的时候(不断往管道写入),write函数也有两种可能:

如果文件状态标志(O_NONBLOCK disable)阻塞(未设置),write调用阻塞

文件状态标志(O_NONBLOCK)非阻塞, write返回-1   errno=EAGAIN.

同时这个例子还可以获取管道内核缓冲区的大小。

#include<unistd.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<fcntl.h>
#include<stdlib.h>
#include<stdio.h>
#include<errno.h>
#include<string.h>

#include<signal.h>
#define ERR_EXIT(m)\
    do\
    {\
        perror(m);\
        exit(EXIT_FAILURE);\
    }while(0)  //宏要求一条语句
int main(int argc,char*argv[])
{
    int pipefd[2];
    if(pipe(pipefd)==-1)
        ERR_EXIT("pipe error");
    int ret;
    int count=0;
    int flags=(pipefd[1],F_GETFL);
    fcntl(pipefd[1],F_SETFL,flags|O_NONBLOCK);//改为非阻塞,写满的话再写就会出错。默认阻塞,写满write就会阻塞
    while(1)
    {
        ret=write(pipefd[1],"a",1);//一个一个写会阻塞,若一下子写的超过64k要写完才返回。
        if(ret==-1){
printf("err=%s\n",strerror(errno));
break;
     } count
++; } printf("count=%d\n",count);//65536字节.管道容量64k,管道容量不等于PIPE_BUF的大小,PIPE_BUF一般4k return 0; }

 

5、当要写入的数据量不大于PIPE_BUF时,LINUX将保证写入的原子性,指多个进程向管道写入数据,各个进程数据连续,不被插入其他进程数据;当要写入的数据量大于PIPE_BUF时,LINUX将不再保证写入原子性。可能会被其他进程插入数据。PIPE_BUF一般为4KB。

阻塞模式并且n<=PIPE_BUF:所有数据原子性写入。可以打印出来,在头文件<linux/limits.h>中。不一定等同于管道容量;

非阻塞模式并且n<=PIPE_BUF:若空间不够,失败返回,不写入字符;

阻塞模式并且n>PIPEBUF:不保证原子性,直到n个字节全部被写完才返回;

非阻塞模式且n>PIPEBUF:失败同样不写入;若可以但不保证原子性。

 

 1 #include<unistd.h>
 2 #include<sys/types.h>
 3 #include<sys/stat.h>
 4 #include<fcntl.h>
 5 #include<stdlib.h>
 6 #include<stdio.h>
 7 #include<errno.h>
 8 #include<string.h>
 9 
10 #include<linux/limits.h>
11 #define TEST_SIZE 68*1024
12 #define ERR_EXIT(m)\
13     do\
14     {\
15         perror(m);\
16         exit(EXIT_FAILURE);\
17     }while(0)  //宏要求一条语句
18 int main(int argc,char*argv[])
19 {
20     printf("pipe_buf=%d\n",PIPE_BUF);
21     int ret;
22     char a[TEST_SIZE];//68KB
23     char b[TEST_SIZE];
24     memset(a,'A',sizeof(a));
25     memset(b,'B',sizeof(b));
26     int pipefd[2];
27     if(pipe(pipefd)==-1)
28         ERR_EXIT("pipe error");
29     
30     pid_t pid;
31     //创建第一个子进程
32     pid=fork();
33     if(pid==0)
34     {
35         close(pipefd[0]);//关闭读端
36         ret=write(pipefd[1],a,sizeof(a));//往管道写端写入68K数据。管道64k
37         printf("apid=%d write %d bytes to pipe\n",getpid(),ret);
38         exit(0);
39     }
40     //再创建一个子进程,写入68k b
41     pid=fork();
42     if(pid==0)
43     {
44         close(pipefd[0]);
45         ret=write(pipefd[1],b,sizeof(b));//写完68k才返回。管道大小64K.
46         printf("bpid=%d write%d bytes to pipe\n",getpid(),ret);
47         exit(0);
48     }
49     //父进程
50     close(pipefd[1]);
51     sleep(1);//使子进程先到write()
52     int fd=open("test.txt",O_WRONLY|O_CREAT|O_TRUNC,0644);
53     char buf[1024*4]={0};//每次接收4k数据
54     int n=1;
55     while(1)
56     {
57         ret=read(pipefd[0],buf,sizeof(buf));//每次接收4k数据
58         if(ret==0)
59             break;//子进程都发完数据了,管道写端都关闭了。跳出循环
60         //没发完的话,每次收到4k,打印最后一个字符。会有穿插,68k远远超出PIPE_BUF
61         printf("n=%02d pid=%d read %d bytes from pipe buf[4095=]%c\n",n++,getpid(),ret,buf[4095]);//打印输出收到的数据
62         write(fd,buf,ret);//每次4k写入文件。
63     }
64     return 0;
65 }

 

posted on 2018-01-30 15:31  wsw_seu  阅读(640)  评论(0编辑  收藏  举报

导航