LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
查看: 1707|回复: 2

2.6.11开始,PIPE_BUF改成65536大小了?

[复制链接]
发表于 2006-4-18 20:33:27 | 显示全部楼层 |阅读模式
最近看本书,书上说PIPE_BUF是4096, 我按着书的例子调试name pipe,写PIPE_BUF的时候,怎么都不对,搞了一下午,硬是把PIPE_BUF的大小摸索出来了,是65536,现在上网一查,果然从2.6.11开始,改成65536了,真是晕死啊。。。

In Linux versions before 2.6.11, the capacity of a pipe was the same as the system page size (e.g., 4096 bytes on x86). Since Linux 2.6.11, the pipe capacity is 65536 bytes.  

但还是有问题:资料上说:
O_NONBLOCK enabled, n <= PIPE_BUF
If there is room to write n bytes to the pipe, then write(2) succeeds immediately, writing all n bytes; otherwise write(2) fails, with errno set to EAGAIN


/* 这是写程序,第一次写入32768,第二次写入42769 */
write.c
...
char w_buf[65536*2];
...
fd=open(pipe,O_CREAT|O_TUNC|O_NONBLOCK,0);
...
ret=write(fd,w_buf,32768);
...
if((ret=write(fd,w_buf,42769))==-1);
if (errno==EAGAI)
print ("write error");
....

/* 这是读程序,一次读10000 */
...
char r_buf[65536*2];
...
fd=open(pipe,O_CREAT|O_TUNC|O_NONBLOCK,0);
while(1)
{
  fd=read(fd,r_buf,10000);
...
}
按着资料上书上说的,我第一次往PIPE里写入32768后,pipe空闲是32768,于是我第二次再次写入42769时,由于42769<IPE_BUF(65536),并且写入数据超过了空闲PIPE缓冲区,此时,write应该返回EAGAIN错误,但是,我的运行结果不是这样的!!!
我运行的结果是,第二次写操作成功返回,写入了32768字节。不知道是什么原因,各位也可在2.6.11以上的机器上调试一下,看结果是什么??

经过我继续摸索,发现当第一次写操作结束使得空闲的PIPE缓冲区<4096,并且第二次写操作写>=4096的时候,第二次写操作便会返回EAGAIN错误。
如果第一次写操作结束使得空闲的PIPE缓冲区>=4096,则会发生上面所述的问题。
 楼主| 发表于 2006-4-19 12:31:57 | 显示全部楼层
怎么没有人响应啊。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2006-4-20 14:51:28 | 显示全部楼层
顶!希望大家能够在自己机器上跑一下。验证一下。
-------------------------------------
以下是读pipe程序:
-------------------------------------
/* linux pipe_buf大小为65536,read一次读取16384大小的内容
*/
#include <sys/types.h>

#include <sys/stat.h>

#include <errno.h>

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <string.h>

#define FIFO_SERVER "/tmp/fifo"



main(int argc,char** argv)

{

        char r_buf[65536*2];

        int  fd;

        int  r_size;

        int  ret_size;

        int  i=0;
        if (argc!=2) {
                printf("Usage : %s number\n",argv[0]);
                exit(1);
        }
        r_size=atoi(argv[1]);

        printf("requred real read bytes %d\n",r_size);

        memset(r_buf,0,sizeof(r_buf));

        fd=open(FIFO_SERVER,O_RDONLY|O_NONBLOCK,0);       
//非阻塞,当无写操作打开,或有写操作打开,但没写数据进去,则此读操作返回-1,当前的errno值为EAGAIN

//        fd=open(FIFO_SERVER,O_RDONLY,0);               
//阻塞,当无写操作打开,或有写操作打开,但没写数据进去,则此读操作阻塞;
//除此之外,造成阻塞的另外一种原因是,FIFO里有数据,但有另外的进程在读;
//阻塞只对本进程的第一个读操作有效,当读操作解除阻塞后,即使FIFO里无数据,余下的读操作均不会阻塞;

        if(fd==-1)

        {

                printf("open %s for read error\n");

                exit(1);       

        }

        while(1)

        {

                ret_size=read(fd,r_buf,r_size);

                if(ret_size==-1)

                        if(errno==EAGAIN)

                                printf("no data avlaible\n");

                printf("%d : real read bytes %d\n",i,ret_size);

                sleep(1);

                i++;
        }       

        pause();

        unlink(FIFO_SERVER);

}

---------------------------------------------
以下是写pipe程序:
---------------------------------------------
#include <sys/types.h>

#include <sys/stat.h>

#include <errno.h>

#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>

#define FIFO_SERVER "/tmp/fifo"

main(int argc,char** argv)

{

        int fd;

        char w_buf[65536*2];

        int real_wnum;

        memset(w_buf,0,sizeof(w_buf));

        if((mkfifo(FIFO_SERVER,O_CREAT|O_EXCL)<0)&&(errno!=EEXIST))

                printf("cannot create fifoserver\n");

               

           fd=open(FIFO_SERVER,O_WRONLY|O_NONBLOCK,0);         //设置非阻塞标志

//        fd=open(FIFO_SERVER,O_WRONLY,0);                //设置阻塞标志

        if(fd==-1)

                if(errno==ENXIO)

                        printf("open error; no reading process\n");
        sleep(10);//用于测试读操作

        real_wnum=write(fd,w_buf,32768);

        if(real_wnum==-1)

        {
                if(errno==EAGAIN)

                        printf("write to fifo error; try later\n");

        }

        else

                printf("real write num is %d\n",real_wnum);

        real_wnum=write(fd,w_buf,65535);       
/*PIPE_BUF为65536
*第一次写32768,空闲区为32768
*写操作非阻塞
*  当第二次写65537(大于PIPE_BUF)时,写入32768(尽量写满空闲区)后返回,有数据没写完
*  当第二次写65535(小于PIPE_BUF,但大于空闲缓冲区)时,写入32768(尽量写满空闲区)后返回,有数据没写完
    这里有个临界点,当空闲区<4096时,第二次写入>=4096的数据时,返回EAGAIN错误
*  当第二次写32767(小于PIPE_BUF,也小于空闲缓冲区)时,可写完所有数据
*写操作阻塞
*  当第二次写65537(大于PIPE_BUF)时,先写一部分,一旦有空闲空间,便接着写,直到写完,成功返回(无原子性)
*  当第二次写65535(小于PIPE_BUF,但大于空闲缓冲区)时,写操作阻塞,直到空闲空间达到写入数据的要求后,一次性写完,返回(原子)
*  当第二次写32767(小于PIPE_BUF,也小于空闲缓冲区)时,可写完所有数据
*/
        if(real_wnum==-1) {

                if(errno==EAGAIN)

                        printf("try later\n");

        } else printf("real write num is %d\n",real_wnum);
}

-------------------------------------------------------------
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表