命名管道Linux

7
我创建了两个线程,一个线程用于读取,另一个线程用于写入。但是我遇到了未定义的行为,有时我只能读取一行,有时可以读取1000行。这对我来说没有多大意义。
我的做法如下: 1. 在main.cpp中使用mkfifo()创建一个FIFO。 2. 启动两个线程,一个用于读取,另一个用于写入。分别是reader.cpp和writer.cpp。
在这些线程中,每个循环都会打开FIFO并关闭它,因为如果我只在循环外执行一次,它就不起作用了,这也让我感到很奇怪。
我一直在寻找好的例子,但我没有找到。
我的问题很简单,如何使FIFO(Reader)等待传入数据并在可用时读取它。它应该能够以4Mhz运行。
我希望有人能帮助我,因为我已经在这个问题上头痛了三天。如果有影响的话,我正在使用Qt 4.8。
编辑:我找到了解决方法:
main.cpp
#include <QtCore/QCoreApplication>
#include "reader.h"
#include "writer.h"
#include <sys/types.h>  // mkfifo
#include <sys/stat.h>   // mkfifo
#include <fcntl.h>

int main(int argc, char *argv[]) {

    QCoreApplication a(argc, argv);

    int fifo = mkfifo("/tmp/fifo", S_IWUSR | S_IRUSR | S_IRGRP | S_IROTH);

    Reader r;
    Writer w;
    r.start();
    w.start();

    return a.exec();
}

writer.h

#ifndef WRITER_H
#define WRITER_H

#include <QThread>
#include <stdio.h>
#include <iostream>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

class Writer : public QThread {

    Q_OBJECT

public:
    explicit Writer(QObject *parent = 0);

private:
    void run();

};

#endif // WRITER_H

reader.h

#ifndef READER_H
#define READER_H

#include <QThread>
#include <stdio.h>
#include <iostream>
#include <errno.h>
#include <string.h>
#include <fcntl.h>

class Reader : public QThread {

    Q_OBJECT

public:
    explicit Reader(QObject *parent = 0);

private:
    void run();

};

#endif // READER_H

writer.cpp

#include "writer.h"

char * phrase = "Stuff this in your pipe and smoke it\n";

using namespace std;

Writer::Writer(QObject *parent) : QThread(parent) {}

void Writer::run() {

    int num, fifo;
    if ((fifo = open("/tmp/fifo", O_WRONLY)) < 0) {
       printf("%s\n", strerror(errno));
       return;
    }
    while (true) {

        if ((num= write(fifo, phrase, strlen(phrase)+1)) < 0) {
            printf("ERROR: %s\n", strerror(errno));
        }
    }
    close(fifo);

}

reader.cpp

#include "reader.h"

using namespace std;

Reader::Reader(QObject *parent) : QThread(parent) {}

void Reader::run() {

    int num, fifo;
    char temp[38];
    if ((fifo = open("/tmp/fifo", O_RDONLY)) < 0) {
        printf("%s\n", strerror(errno));
        return;
    }
    while (true) {
        if ((num = read(fifo, temp, sizeof(temp))) < 0) {
            printf("%s\n", strerror(errno));
        }
        printf("In FIFO is %d %s \n", num, temp);
    }
    close(fifo);
}

1
人们会因为最疯狂的原因对你这样做。每个人都会遇到这种情况。我不会担心它,而是开始逐渐习惯它。我知道这很悲哀。点赞了,发现这真的很有用。 - Eduard Luca
@Eduard Luca 非常感谢您的反馈,我很高兴您觉得它有用。 :) - fonZ
2个回答

4
基本的read()和write()函数不能保证读取或写入所有可用的数据。
你需要使用以下代码:
int tot = 0;
while (tot < sizeof(temp))
{
    num = read(fifo, temp + tot, sizeof(temp) - tot);
    if (num < 0)
        break;
    tot += num;
}

对于写入操作同理。


1
如果我理解正确,它将读取直到没有可读取的内容。然而,这个过程必须持续到手动关闭为止。基本上数据可能随时出现,而且FIFO并不总是有数据。 - fonZ
1
我应该澄清一下,我的回答是为什么您会得到未定义行为的答案。如果有一个可用/可以放置一个字节,read()和write()将始终读取或写入至少一个字节。 - Joel Klinghed
1
这就是我不理解的地方,通常FIFO应该能够接收所有数据并将其缓冲,直到被读取。即使它是空的,进程也应该能够等待数据到达。 - fonZ
1
FIFO就像你所描述的那样,它可以完成所有这些操作。只是当你调用read()函数时,它不能保证一次性返回所有可用的数据。因此,如果FIFO包含12个字节的数据,则read(fifo, buffer, 100)将返回1到12之间的任何值,这是正确的。如果你反复调用read()函数,你将获得所有12个字节的数据(或者你可能在第一次调用中就获取了所有数据)。 - Joel Klinghed
2
write()的工作方式完全相同,如果您希望写入12个字节,则可能会写入1到12个字节,这也是正确的。如果您需要知道read()或write()是否会阻塞或直接获取数据,则应使用select()。 - Joel Klinghed
显示剩余2条评论

1

当我定期打开和关闭单个管道时,遇到了同样的问题。在读取器进程中重新创建管道(当遇到EOF时)将是一个解决方案。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接