分类: LINUX
2009-07-14 23:45:49
管道或FIFO的open、read、write以及相关的阻塞与非阻塞是这一部分的难点,这些概念不是很难,但是揉在一起就让人感觉理不清头绪, 仔细研究了这一部分很多遍,总算有点头绪。借用《UNP》上的表:
当前操作 |
Pipe或FIFO 现有操作 |
返回 | |
阻塞 |
O_NONBLOCK | ||
Open (FIFO O_RDONLY) |
Open(FIFO, O_WRONLY) |
成功 |
成功 |
Open(FIFO, O_RDONLY)或无open |
阻塞到 Open(FIFO, O_WRONLY) |
成功 | |
Open (FIFO O_WRONLY) |
Open(FIFO O_RDONLY) |
成功 |
成功 |
Open(FIFO, O_WRONLY)或 无open |
阻塞到 Open(FIFO,O_RDONLY) |
ENOXIO | |
从空pipe或空FIFO Read |
管道或FIFO打开来写 |
阻塞到pipe或FIFO中有数据 Pipe或FIFO不再为写打开 |
EAGAIN |
管道或FIFO不是打开来写 |
返回0(EOF) |
返回0(EOF) | |
往管道或FIFO write |
管道或FIFO打开来读 |
|
|
管道或FIFO不是打开来读 |
SIGPIPE |
SIGPIPE |
1、open Open(FIFO, O_WRONLY)与Open(FIFO, O_RDONLY)要成对出现,否则就会阻塞对于设置了O_NONBLOCK标志的,Open(FIFO, O_WRONLY)之前必须有Open(FIFO, O_RDONLY),否则会返回ENOXIO。 这一点都比较好理解。
2、read and write 这一点比较乱,还是用代码说话比较好,下面是代码片段。
if ( (childpid = Fork()) == 0) { /* child */
readfd = Open(FIFO1, O_RDONLY, 0);
writefd = Open(FIFO2, O_WRONLY, 0);
…
//(4)
Close(readfd); //管道或FIFO不是打开来读
//
//// 从空pipe或空FIFORead
if ( (n = Read(readfd, buff, MAXLINE)) == 0) //(2)返回EOF
err_quit("end-of-file while reading pathname"); //(1)阻塞
…
exit(0);
}
/* 4parent */
writefd = Open(FIFO1, O_WRONLY, 0);
readfd = Open(FIFO2, O_RDONLY, 0);
…
Fgets(buff, MAXLINE, stdin);
…
// (2)
Close(writefd); //管道或FIFO不是打开来写
//
//(1) //管道或FIFO打开来写
Len = 0;
//
Write(writefd, buff, len); //(4)产生SIGPIPE
标记(1)、(2)、(3)、(4)是添加的代码实现上面表格中标记的功能。第(3)中情况,要注意写不能溢出缓冲区就可以了,否则情况就难以预知了。
不知道这样能不能看明白,说明一下:
(1)FIFO打开来写的,但写入0字节,模拟使FIFO为空,子进程Read就会阻塞。
(2)close(writefd)使FIFO不再为写打开, 子进程Read会返回EOF。
(4)子进程close(readfd)使FIFO不再打开来读, 父进程Write会产生SIGPIPE。