linux系统编程之管道(二):管道读写规则


一,管道读写规则

当没有数据可读时

  • O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。
  • O_NONBLOCK enable:read调用返回-1,errno值为EAGAIN。

当管道满的时候

  • O_NONBLOCK disable: write调用阻塞,直到有进程读走数据
  • O_NONBLOCK enable:调用返回-1,errno值为EAGAIN

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

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

当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。

当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

二,验证示例

示例一:O_NONBLOCK disable:read调用阻塞,即进程暂停执行,一直等到有数据来到为止。

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

 main( fds[(pipe(fds) == -=(pid == -(pid == ]);
        sleep(],,]);
     buf[] = {],buf, 

结果:

<unistd.h><stdlib.h><fcntl.h> main( fds[(pipe(fds) == -=(pid == -(pid == ]); sleep(],,]); buf[] = { flags = fcntl(fds[], F_GETFL); fcntl(fds[],F_SETFL,flags | O_NONBLOCK); = read(fds[],buf,(ret == -

结果:

<unistd.h><stdlib.h><fcntl.h> main( fds[(pipe(fds) == -=(pid == -(pid == ]); ]); buf[] = {= read(fds[],buf,

结果:

<unistd.h><stdlib.h><fcntl.h><signal.h> sighandler( main( fds[(signal(SIGPIPE,sighandler) ==(pipe(fds) == -=(pid == -(pid == ]); ]); sleep(); = write(fds[],,(ret == - sighandler(

结果:

<unistd.h><stdlib.h><fcntl.h> main( fds[(pipe(fds) == - count = (= write(fds[],,); (ret == -++

结果:

<unistd.h><stdlib.h><fcntl.h> main( fds[(pipe(fds) == - count = flags = fcntl(fds[],F_SETFL,flags|(= write(fds[],,); (ret == -++

结果:

O_NONBLOCK flag is set (see below). Different implementations have different limits for the pipe capacity. Applications should not rely on a particular capacity: an application should be designed so that a reading process consumes data as soon as it is available, so that a writing process does not remain blocked. 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 i386). Since Linux 2.6.11, the pipe capacity is 65536 bytes.

三,管道写与PIPE_BUF关系

man帮助说明:
PIPE_BUF
       POSIX.1-2001 says that write(2)s of less than PIPE_BUF bytes must be
       atomic: the output data is written to the pipe as a contiguous
       sequence.  Writes of more than PIPE_BUF bytes may be nonatomic: the
       kernel may interleave the data with data written by other processes.
       POSIX.1-2001 requires PIPE_BUF to be at least 512 bytes.  (On Linux,
       PIPE_BUF is 4096 bytes.)  The precise semantics depend on whether the
       file descriptor is nonblocking (O_NONBLOCK), whether there are
       multiple writers to the pipe, and on n, the number of bytes to be
       written:

       O_NONBLOCK disabled, n <= PIPE_BUF
              All n bytes are written atomically; write(2) may block if
              there is not room for n bytes to be written immediately
       阻塞模式时且n<PIPE_BUF:写入具有原子性,如果没有足够的空间供n个字节全部写入,则阻塞直到有足够空间将n个字节全部写入管道       
       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.
      非阻塞模式时且n<PIPE_BUF:写入具有原子性,立即全部成功写入,否则一个都不写入,返回错误
       O_NONBLOCK disabled, n > PIPE_BUF
              The write is nonatomic: the data given to write(2) may be
              interleaved with write(2)s by other process; the write(2)
              blocks until n bytes have been written.
      阻塞模式时且n>PIPE_BUF:不具有原子性,可能中间有其他进程穿插写入,直到将n字节全部写入才返回,否则阻塞等待写入
       O_NONBLOCK enabled, n > PIPE_BUF
              If the pipe is full, then write(2) fails, with errno set to
              EAGAIN.  Otherwise, from 1 to n bytes may be written (i.e., a
              "partial write" may occur; the caller should check the return
              value from write(2) to see how many bytes were actually
              written), and these bytes may be interleaved with writes by
              other processes.
   非阻塞模式时且N>PIPE_BUF:如果管道满的,则立即失败,一个都不写入,返回错误,如果不满,则返回写入的字节数为1~n,即部分写入,写入时可能有其他进程穿插写入
  • 当要写入的数据量不大于PIPE_BUF时,linux将保证写入的原子性。
  • 当要写入的数据量大于PIPE_BUF时,linux将不再保证写入的原子性。

注:管道容量不一定等于PIPE_BUF

示例:当写入数据大于PIPE_BUF时

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


 ERR_EXIT(m) \
        ( TEST_SIZE 68*1024

 main(, , ,  pipefd[ ret = (ret == -= (pid == )
= write(pipefd[], a, = (pid == )
= write(pipefd[], b, = (pid == )
= write(pipefd[], c,  fd = open(, O_WRONLY | O_CREAT | O_TRUNC,  buf[*] = { n =  (= read(pipefd[], buf,  (ret == , n++, getpid(), ret, buf[ 

结果:

QQ截图20130715235256

QQ截图20130715235322

可见各子进程间出现穿插写入,并没保证原子性写入,且父进程在子进程编写时边读。

相关内容