【问题标题】:Unnamed pipe gets blocked although there is data to read尽管有数据要读取,但未命名的管道被阻塞
【发布时间】:2014-05-13 05:42:10
【问题描述】:

我在使用 C 中的未命名管道或“fifos”时遇到了一些问题。我有两个可执行文件:一个尝试读取,另一个尝试写入。阅读器只能执行一次。我尝试编写一个简单的代码来显示我的问题,所以它读取了 10 次然后关闭。但是,编写器应该执行多次(在我的原始程序中,它不能一次执行两次:您必须等待它完成才能再次运行它)。

这段代码的问题是:它只在另一个消息到达时打印传入的消息。似乎它会被阻止,直到它收到另一条消息。我不知道发生了什么,但似乎“读取”行会阻止程序,尽管有数据要读取,并且当我发送新数据时它会再次工作。

我尝试了另一件事:如您所见,作者关闭了文件描述符。阅读器打开文件描述符两次,因为它会找到 EOF 并在没有找到的情况下解锁。我尝试消除这些行(作者不会关闭 fd,读者只会打开 fd 一次,消除第二个“open()”)。但由于某种原因,如果我这样做,它就会解除阻塞。为什么会这样?

这是我的代码:

读者:

int main () {

int fd;

static const std::string FILE_FIFO = "/tmp/archivo_fifo";

mknod ( static_cast<const char*>(FILE_FIFO.c_str()),S_IFIFO|0666,0 );

std::string mess = "Hii!! Example";

//open:
fd = open ( static_cast<const char*>(FILE_FIFO.c_str()),O_WRONLY );

//write:
write ( fd, static_cast<const void*>(mess.c_str()) ,mess.length() );

std::cout << "[Writer]  I wrote " << mess << std::endl;

//close:
close ( fd );
fd = -1;

std::cout << "[Writer] END" << std::endl;
exit ( 0 );
}

作家:

int main () {
int i,fd;
static const int BUFFSIZE = 100;
static const std::string name = "/tmp/archivo_fifo";
mknod ( static_cast<const char*>(name.c_str()),S_IFIFO|0666,0 );
char buffer[BUFFSIZE];

i=0;
fd = open ( name.c_str(),O_RDONLY );
while (true) {
    i++;
    std::cout << "Waiting to read Fifo: "<< i << std::endl;
    ssize_t bytesLeidos = read ( fd,static_cast<void*>(buffer),BUFFSIZE);
    fd = open ( name.c_str(),O_RDONLY );
    std::string mess = buffer;
    mess.resize ( bytesLeidos );
    std::cout << "[Reader] I read: " << mess << std::endl;
    sleep(3);
    if (i==10) break;

}
close ( fd );
fd = -1;
unlink ( name.c_str() );

std::cout << "[Reader] END" << std::endl;
exit ( 0 );

}

提前致谢。请原谅我的英语不好

【问题讨论】:

  • 这段代码看起来不像C,那不是C++吗?
  • 是的,但只有不重要的部分,如打印。我认为 FIFO 库属于 GNU C 库。
  • 您仍然应该使用它所在的语言而不是它不使用的语言进行标记。C 和 C++ 的细节之间存在很大差异。
  • 这不应被标记为c
  • 好的,好的...我会编辑它。但这对我来说没有意义。但是问题已经解决了,所以……好吧。

标签: c++ concurrency pipe


【解决方案1】:

您应该使用 select 调用来确定管道的 fd 上是否有任何数据可用。

看看

http://en.wikipedia.org/wiki/Select_(Unix)

【讨论】:

    【解决方案2】:

    你已经打开了blocking mode中的文件:

    如果某个进程打开了管道进行写入并且 O_NONBLOCK 已清除,则 read() 将阻塞调用线程,直到某些数据被写入或管道被所有打开管道进行写入的进程关闭。

    取决于您的目标,您应该同步管道的读取器和写入器,或者对读取器使用非阻塞模式。阅读poll, epoll, select

    【讨论】:

    • 但我希望它被阻止...我不知道为什么它会被阻止虽然有数据要读取。
    【解决方案3】:

    我一直在阅读有关未命名管道的更多信息,现在我明白了这个问题。我写道:

    阅读器打开文件描述符两次,因为它会找到 EOF 并在没有找到时解锁。我尝试消除这些行(作者不会关闭 fd,读者只会打开 fd 一次,消除第二个“open()”)。但由于某种原因,如果我这样做,它就会解除阻塞。为什么会这样?

    它解除阻塞是因为其他进程关闭了,所以操作系统无论如何都会关闭文件描述符。这就是为什么虽然我没有写 close(fd) 它会解除阻塞。

    阻塞fifo可以解除阻塞的唯一方法是:

    1) 有数据要读取 2)其他程序关闭了文件描述符。如果没有数据要读取并且写入器关闭了文件描述符(即使文件描述符在读取器中打开),read() 会返回 0 并解除阻塞。

    所以我的解决方案是:重新设计我的程序,使其始终打开编写器的文件描述符。这意味着:现在只有一个可执行文件。我很确定我可以用两个可执行文件完成它,但我可能需要信号量或类似的东西来同步,所以如果作者的 fd 关闭,它就不会尝试读取。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-09-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多