1. 命名管道: FIFO
命名管道是一种特殊类型的文件,
它在文件系统中以文件名的形式存在,但它的行为却和匿名管道类似;
2. FIFO文件与普通文件之间的区别:
A. 程序不能以O_RDWR模式打开FIFO文件进行读写操作,
这样做的后果并未明确定义,
如果一个管道以读/写方式打开, 进程就会从这个管道读回它自己的输出.
如果需要在程序之间双向传递数据,
最好是使用一对FIFO或管道,一个方向使用一个;
或者(但不常用),采用先关闭再重新打开FIFO的方法来明确改变数据流的方向.
B. 对open_flag(open函数的第二个参数)的"O_NONBLOCK"选项的用法;
3. open_flag标志(O_RDONLY, O_WRONLY和O_NONBLOCK)的4种合法组合方式:
A. 阻塞方式读open
- open(const char *path, O_RDONLY);
在这种方式下,open调用将阻塞,
除非有一个进程以写的方式打开同一个FIFO,
否则它不会返回。
B. 非阻塞方式读open
- open(const char *path, O_RDONLY | O_NONBLOCK);
即使没有其它的进程以写的方式打开FIFO,
这个open调用也将成功并立即返回。
C. 阻塞方式写open
- open(const char *path, O_WRONLY);
在这种情况下,open调用将阻塞,
直到有一个进程以读方式打开同一个FIFO为止。
D. 非阻塞方式写open
- open(const char *path, O_WRONLY | O_NONBLOCK);
这个函数调用总是立即返回,
如果 没有进程以读方式打开FIFO文件,
open调用将返回一个错误-1并且FIFO也不会打开。
如果 有一个进程以读方式打开FIFO文件,
那么可以通过这个函数返回的文件描述符对这个FIFO进行写操作。
close调用行为并不受O_NONBLOCK标志的影响.
open模式的最常见的组合形式:
A. 阻塞方式读open + 阻塞方式写open
这样的形式, 它允许先启动读进程,并在open调用中等待,
当写进程打开FIFO时,
两个进程在open调用处取得同步,两个程序继续运行。
B. 非阻塞方式读open + 阻塞方式写open
这时,读进程在即使没有写进程存在的情况下,仍能执行open调用并继续执行.
随后写进程开始执行,
因为FIFO已被读进程打开,它在open调用后立即继续执行.
4. 使用O_NONBLOCK对FIFO的read和write操作约定:
对一个空的,阻塞的FIFO(即没有用O_NONBLOCK标志打开)的read调用将等待,
直到有数据可以读时才执行。
与此相反,
对一个空的,非阻塞的FIFO的read调用立即返回0字节。
对一个完全阻塞FIFO的write调用将等待,
直到数据可以被写入时才继续执行。
如果FIFO不能接收所有写入的数据,它将按下面的规则执行:
如果 请求写入的数据长度 <= PIPE_BUF字节
调用失败,数据不能写入。
如果 请求写放的数据长度 > PIPE_BUF字节
将写入部分数据,返回实际写入的字节数,返回值也可能是0.
FIFO的长度定义
在limits.h中的
#define PIPE_BUG语句中定义,
linux下的值通常是4096字节。
FIFO的原子性:
系统规定, 在一个以O_WRONLY方式打开的FIFO中,
如果写入的数据长度 <= PIPE_BUF字节,
那么或者写入全部字节,或者一个字节都不写入。
如果保证所有写请求是发往一个阻塞的FIFO的,
并且每个写请求的数据长度 <= PIPE_BUF字节,
系统将会保证数据决不会交错在一起。
所以,通常将每次通过FIFO传递的数据长度限制为PIPE_BUF字节是个好方法。
5. 示例,
生产者--消费者模型
以
阻塞方式读open + 阻塞方式写open;
写进程读取文件数据并发送到FIFO;
读进程读取FIFO中的数据并显示;
代码如下:
producer.c
- /*
- * \File
- * producer.c
- *
- */
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <fcntl.h>
- #include <limits.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #define FIFO_NAME "test_fifo"
- #define BUFFER_SIZE (512)
- #define TESTF_IN "test.dat"
- #define OP_LEN (100)
- FILE* fp_in;
- int main(char argc, char* argv[])
- {
- int pipe_fd;
- int res;
- int open_mode = O_WRONLY;
- int bytes_sent = 0;
- int bytes_read = 0;
- char buffer[BUFFER_SIZE + 1];
- if (access(FIFO_NAME, F_OK) == -1)
- {
- res = mkfifo(FIFO_NAME, 0777);
- if (res != 0)
- {
- fprintf(stderr, "Could not create fifo %s\n", FIFO_NAME);
- exit(EXIT_FAILURE);
- }
- }
- printf("Process %d opening FIFO O_WRONLY\n", getpid());
- pipe_fd = open(FIFO_NAME, open_mode);
- printf("Process %d result %d\n", getpid(), pipe_fd);
- if (pipe_fd != -1)
- {
- if ((fp_in = fopen(TESTF_IN, "r")) < 0)
- {
- fprintf(stderr, "Open input file failed:%s\n", TESTF_IN);
- exit(EXIT_FAILURE);
- }
- while ((bytes_read = fread(buffer, sizeof(char), OP_LEN, fp_in)))
- {
- printf("PRODUCE: %d, %s", bytes_read, buffer);
- res = write(pipe_fd, buffer, bytes_read);
- if (res == -1)
- {
- fprintf(stderr, "Write error on pipe\n");
- exit(EXIT_FAILURE);
- }
- bytes_sent += res;
- memset(buffer, 0, BUFFER_SIZE);
- if (feof(fp_in) != 0)
- {
- printf("read over\n");
- break;
- }
- }
- (void)close(pipe_fd);
- fclose(fp_in);
- }
- else
- {
- exit(EXIT_FAILURE);
- }
- return 0;
- }
consumer.c
- /*
- * \File
- * consumer.c
- *
- */
- #include <unistd.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <fcntl.h>
- #include <limits.h>
- #include <sys/types.h>
- #include <sys/stat.h>
- #define FIFO_NAME "test_fifo"
- #define BUFFER_SIZE (512)
- #define OP_LEN (100)
- int main(char argc, char* argv[])
- {
- int pipe_fd;
- int res;
- int open_mode = O_RDONLY;
- char buffer[BUFFER_SIZE + 1];
- int bytes_read = 0;
- memset(buffer, '\0', sizeof(buffer));
- printf("Process %d opening FIFO O_RDONLY\n", getpid());
- pipe_fd = open(FIFO_NAME, open_mode);
- printf("Process %d result %d\n", getpid(), pipe_fd);
- if (pipe_fd != -1)
- {
- do
- {
- res = read(pipe_fd, buffer, OP_LEN);
- printf("CONSUME: %d, %s\n", res, buffer);
- bytes_read += res;
- memset(buffer, 0, BUFFER_SIZE);
- if (res < OP_LEN)
- {
- printf("read over\n");
- break;
- }
- } while (res > 0);
- (void)close(pipe_fd);
- }
- else
- {
- exit(EXIT_FAILURE);
- }
- printf("Process %d finished, %d bytes read\n", getpid(), bytes_read);
- exit(EXIT_SUCCESS);
- return 0;
- }
gcc
- $ gcc -o producer producer.c
- $ gcc -o consumer consumer.c