阅读 64

进程间通信(六)

读取与写入FIFO

使用O_NONBLOCK模式会影响作用在FIFO上的read与write调用的行为。

在一个空的阻塞FIFO(例如,没有使用O_NONBLOCK打开的)上的read调用将会等待直到有数据可以读取。相反,在非阻塞且没有数据的FIFO上进行read调用将会返回0字节。

在一个完全阻塞的FIFO上的write调用将会等待直到数据可以写入。在一个不能全部接受所有将要写入数据的FIFO上的write调用将会:
如果请求PIPE_BUF字节或是小于且数据不能写入时将会失败。
如果请求大于PIPE_BUF字节将会写入部分数据,返回实际写入的字节数据,其值为0。

FIFO的大小是一个重要的考虑因素。在每次可以有多少数据在FIFO中存在一个系统相关的限制。这就是#define PIPE_BUF值,通常 、定义在limits.h中。在Linux与许多其他的类Unix系统,这个值通常为4096字节,但是在某些系统上,这个值可以小至512字节。系统默认在一个使用O_WRONLY模式打开的FIFO上执行PIPE_BUF或是更少字节的写入操作,其结果则是全部写入或是没有任何写入。

尽管这个限制在单一FIFO写入端与单一FIFO读取端的情况下并不是十分重要,但是在使用一个FIFO允许多个程序向一个FIFO读取端发送请求的情况下则是十分常见的。如果多个不同的程序同时尝试向FIFO写入数据,由不同程序来的数据块交错在一起的情况是很严重的,每一个write操作都应是原子的。你认为呢?

然而,如是我们保证我们所有的write请求都发送到阻塞FIFO,而且在大小上小于PIPE_BUF字节,系统将会保证数据不会交错在一起。通常,严格限制通过FIFO发送PIPE_BUF字节大小的数据块是一个好主意,除非我们只使用一个读取端与一个写入端。

试验--使用FIFO的进程交互

要演示不相关的进程如何使用有名管道进行交互,我们需要两个单独的程序,fifo3.c与fifo4.c。

1 第一个程序是我们的生产者程序。如果需要他会创建管道,然后尽快向其中写入数据。

注意,为了演示的目的,我们并不介意数据是什么是,所以我们并不初始化一个缓冲区。

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

#define FIFO_NAME     "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF
#define TEN_MEG    (1024 * 1024 * 10)

int main()
{
    int pipe_fd;
    int res;
    int open_mode = O_WRONLY;
    int bytes_sent = 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)
    {
        while(bytes_sent < TEN_MEG)
        {
            res = write(pipe_fd, buffer, BUFFER_SIZE);
            if (res == -1)
            {
                fprintf(stderr, "Write error on pipe/n");
                exit(EXIT_FAILURE);
            }
            bytes_sent += res;
        }
        (void)close(pipe_fd);
    }
    else
    {
        exit(EXIT_FAILURE);
    }

    printf("Process %d finished/n", getpid());
    exit(EXIT_SUCCESS);
}

2 我们的第二个程序,消费者,比较简单。他由FIFO中读取并丢弃数据。

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

#define FIFO_NAME "/tmp/my_fifo"
#define BUFFER_SIZE PIPE_BUF

int main()
{
    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, BUFFER_SIZE);
            bytes_read += res;
        }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);
}

当我们同时运行这些程序,使用time命令来统计读取的时间,我们会得到下面的输出:

$ ./fifo3 &
[1] 375
Process 375 opening FIFO O_WRONLY
$ time ./fifo4
Process 377 opening FIFO O_RDONLY
Process 375 result 3
Process 377 result 3
Process 375 finished
Process 377 finished, 10485760 bytes read
real    0m0.053s
user    0m0.020s
sys     0m0.040s
[1]+  Done                    fifo3

文章分类
代码人生
文章标签
版权声明:本站是系统测试站点,无实际运营。本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 XXXXXXo@163.com 举报,一经查实,本站将立刻删除。
相关推荐