1

这是制作人。

// speak.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define FIFO_NAME "american_maid"

int main(void)
{
    char s[300];
    int num, fd;

    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    printf("waiting for readers...\n");
    fd = open(FIFO_NAME, O_WRONLY);
    printf("got a reader--type some stuff\n");

    while (gets(s), !feof(stdin)) {
        if ((num = write(fd, s, strlen(s))) == -1)
            perror("write");
        else
            printf("speak: wrote %d bytes\n", num);
    }

    return 0;
}

这就是消费者。

//tick.c
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include <string.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

#define FIFO_NAME "american_maid"

int main(void)
{
    char s[300];
    int num, fd;

    mknod(FIFO_NAME, S_IFIFO | 0666, 0);

    printf("waiting for writers...\n");
    fd = open(FIFO_NAME, O_RDONLY);
    printf("got a writer\n");

    do {
        if ((num = read(fd, s, 300)) == -1)
            perror("read");
        else {
            s[num] = '\0';
            printf("tick: read %d bytes: \"%s\"\n", num, s);
        }
    } while (num > 0);

    return 0;
}

当我运行它们时,生产者输出,

waiting for readers...

和消费者输出,

waiting for writers...

说话找不到读者,打勾。从这里我得到的理论来看,open() (speak.c) 将一直​​被阻塞,直到open() (tick.c) 被打开。反之亦然。所以我猜有一个僵局或发生了什么事。我需要一个解决方案。

4

2 回答 2

0

看起来您在读者和作者之间存在竞争条件。

要解决此问题,您需要一种在编写器“活动”之前不启动阅读器的方法。为此,我建议在作者准备好时制作一个管道并写入它。然后,当从 fork 的读取端读取成功时,fifo 已准备好,读取器应该工作。

您需要在此处使用分叉,因为在父进程和子进程之间协调互斥锁非常重要,并且正确完成的管道更容易。

另外,你打mknod()了两次电话。当然,它会返回 -1 errno == EEXIST,但要更加小心。为避免这种情况,请让 reader 和 writer 成为一个将路径作为参数的函数。

将您的作者重写为int speak(const char *fifo, int pipefd),将您的读者重写为int tick(const char *fifo).

然后像这样制作一个包装器:

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>

const char fifo_name[] /* = ... */;

int speak(const char *fifo, int pipefd);
int tick(const char *fifo);

int main() {
    int pipefd[2];
    pipe(pipefd);

    mknod(fifo_name, S_IFIFO | 0666, 0);

    if (fork() == 0) {
        close(pipefd[0]);
        return speak(fifo_name, pipefd[1]);
    } else {
        close(pipefd[1]);
        char foo;
        read(pipefd[0], &foo, 1);
        return tick(fifo_name);
    }
}

修改您的编写器以在创建 fifo 之后(即在调用 之后)将一个字节(任何内容)打印到传递的 fd open(..., O_WRONLY)

不要逐字使用我的代码,因为为了简洁起见,我省略了错误检查。

于 2012-05-13T08:22:40.073 回答
0

它在我的环境中运行正常。如果 reader 和 writer 准备好, open 将返回。因为 open 被阻塞了,所以在我看来, mknod 函数是成功的。可能是您在不同的路径上执行这两个过程。

于 2012-05-14T10:47:56.710 回答