非阻塞并行FIFO

时间:2015-07-02 11:30:41

标签: c linux

我对两个程序的交互有问题:

计划I 必须定期检查是否有来自计划II的数据。这应该是非阻塞的。

程序II 可以在多个实例中运行,因此是并行的。它将一些数据发送到程序I然后退出。数据的确切顺序并不重要,如果在1秒后接收到1秒后发送的数据就足够了。

我的第一种方法是使用FIFO: "服务器"

int main()
{
int fd;
unlink("/tmp/ctl_fifo");
if (mkfifo("/tmp/ctl_fifo", 0666) == -1)
{
    printf("Error creating FIFO\n");
}

while (true)
{
    if ((fd = open("/tmp/ctl_fifo", O_RDONLY | O_NONBLOCK)) < 0)
    {
        printf("Error opening FIFO\n");
    }
    struct timeval timeout;
    timeout.tv_sec = 0;
    timeout.tv_usec = 2000;
    fd_set set;
    FD_ZERO(&set);
    FD_SET(fd, &set);
    select(fd + 1, &set, NULL, NULL, &timeout);
    if (FD_ISSET(fd, &set))
    {
        char buf[20];
        int r = read(fd,buf, sizeof(buf)); 
        printf("%s\n", buf);
    }
    sleep(1);
}
return 0;
}

&#34;客户机&#34;

int main()
{
while (true)
{
int fd;
fd = open("/tmp/ctl_fifo", O_WRONLY);
if (fd < 0)
{
    printf("Error opening fifo\n");
}
char buf[] = "Blablubb";
write(fd, buf, sizeof(buf));
sleep(0.1);
}
return 0;
}

问题在于数据可能会被扰乱。输出看起来像这样:

Blablubb
ablubb
ubb
b
Blablubb
...

我的问题是:我做错了什么?有没有办法确保数据不会被扰乱?或者是否有完全不同的方法来处理这个问题?

1 个答案:

答案 0 :(得分:2)

首先,您有严重的资源泄漏;每次你的循环运行时open一个新流,并在循环结束时迭代流泄漏,漂浮在稀薄的空气中,好像它从未存在过......问题是它确实存在,并且你没有close

其次,当您使用O_NONBLOCK打开您的信息流时,您不需要使用select

read会在没有任何内容可读时立即返回(错误值),并使用O_NONBLOCK打开流。

int r = read(fd,buf, sizeof(buf)); 
printf("%s\n", buf);

read会返回ssize_t(签名等效于size_t)。因此int r应为ssize_t r

继续(从前一段)到printf ...

printf("%s\n", buf); // THIS IS WRONG!

您需要先检查r,然后开始。完全有可能没有收到任何字节,buf包含纯垃圾。也可以合并两个写入(并且最终只能打印其中一个)。

为了简单起见,我建议您一次接收(并打印)一个字节,除非您收到'\0';打印'\n&#39;而不是'\0'。像这样:

int fd = open("/tmp/ctl_fifo", O_RDONLY | O_NONBLOCK);
if (fd < 0)
{
    printf("Error opening FIFO\n");
}

for (;;)
{
    unsigned char c;
    ssize_t r = read(fd, &c, 1);
    if (r < 0 && errno == EAGAIN) {
        /* read sets EAGAIN when no data is available on otherwise valid
         * non-blocking streams, and returns -1... so we continue looping
         * when that happens */
        continue;
    }
    if (r <= 0) {
        /* Any value less than zero without errno == EAGAIN should terminate
         * ... and r == 0 means EOF */
        break;
    }
    putchar(c == '\0' ? '\n' : c);
}

close(fd);