因为 fifoWriter 已经创建了命名管道,所以 fifoReader 只需要利用标准的 open 调用来通过备份文件来获取到管道中的内容:
const char* file = "./fifoChannel"; int fd = open(file, O_RDONLY);
这个文件的是以只读打开的。
然后这个程序进入一个潜在的无限循环,在每次循环时,尝试读取 4 字节的块。read 调用:
ssize_t count = read(fd, &next, sizeof(int));
返回 0 来暗示该流的结束。在这种情况下,fifoReader 跳出循环,关闭命名管道,并在终止前 unlink 备份文件。
在读入 4 字节整数后,fifoReader 检查这个数是否为质数。这个操作代表了一个生产级别的读取器可能在接收到的字节数据上执行的逻辑操作。在示例运行中,在接收到的 768000 个整数中有 37682 个质数。
重复运行示例, fifoReader 将成功地读取 fifoWriter 写入的所有字节。这不是很让人惊讶的。这两个进程在相同的机器上执行,从而可以不用考虑网络相关的问题。命名管道是一个可信且高效的 IPC 机制,因而被广泛使用。
下面是这两个程序的输出,它们在不同的终端中启动,但处于相同的工作目录:
% ./fifoWriter 768000 ints sent to the pipe. ### % ./fifoReader Received ints: 768000, primes: 37682
消息队列
管道有着严格的先入先出行为:第一个被写入的字节将会第一个被读,第二个写入的字节将第二个被读,以此类推。消息队列可以做出相同的表现,但它又足够灵活,可以使得字节块可以不以先入先出的次序来接收。
正如它的名字所提示的那样,消息队列是一系列的消息,每个消息包含两部分:
- 荷载,一个字节序列(在 C 中是 char)
- 类型,以一个正整数值的形式给定,类型用来分类消息,为了更灵活的回收
看一下下面对一个消息队列的描述,每个消息由一个整数类型标记:
+-+ +-+ +-+ +-+ sender--->|3|--->|2|--->|2|--->|1|--->receiver +-+ +-+ +-+ +-+
在上面展示的 4 个消息中,标记为 1 的是开头,即最接近接收端,然后另个标记为 2 的消息,最后接着一个标记为 3 的消息。假如按照严格的 FIFO 行为执行,消息将会以 1-2-2-3 这样的次序被接收。但是消息队列允许其他收取次序。例如,消息可以被接收方以 3-2-1-2 的次序接收。
mqueue 示例包含两个程序,sender 将向消息队列中写入数据,而 receiver 将从这个队列中读取数据。这两个程序都包含的头文件 queue.h 如下所示:
示例 4. 头文件 queue.h
#define ProjectId 123 #define PathName "queue.h" /* any existing, accessible file would do */ #define MsgLen 4 #define MsgCount 6 -
typedef struct { long type; /* must be of type long */ char payload[MsgLen + 1]; /* bytes in the message */ } queuedMessage;
(编辑:ASP站长网)
|