从管道读取时,为什么libc ++ getline会阻塞,而libstdc ++ getline却不会呢? [英] Why does libc++ getline block when reading from pipe, but libstdc++ getline does not?

查看:107
本文介绍了从管道读取时,为什么libc ++ getline会阻塞,而libstdc ++ getline却不会呢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

使用getline函数的libc++版本的程序在从管道读取输入时将阻塞,直到管道的缓冲区已满.

A program that uses the libc++ version of the getline function will block when it reads input from a pipe until the pipe's buffer is full.

对于getline函数的libstdc++版本,同样是:在这里,该函数将立即读取并在输入可用时立即返回一行输入.

The same is NOT true for the libstdc++ version of the getline function: Here the function immediately reads and returns a line of input as soon as it becomes available.

我应该期望libstdc++libc++之间的这种行为差异吗? [我在这里不是要征求意见,我只是对管道不甚了解,也对实现C ++标准库的困难不甚了解.对我来说,这种行为上的差异肯定是令人惊讶的,但是也许有人知道得更多,并且可以向我保证这种差异是可以预期的,也许这仅仅是实现细节?]

Should I expect this difference in behaviour between libstdc++ and libc++? [ I am not fishing for an opinion here, I simply don't know enough about pipes nor the difficulties of implementing a C++ standard library. To me this difference in behaviour certainly was surprising, but maybe someone knows better and can assure me that such differences are to be expected, that maybe this is simply an implementation detail?]

更重要的是,我该怎么做才能使libc++的行为像libstdc++一样?也就是说,getline函数不应等到管道缓冲区已满,它应该在可用时立即返回一行输入.

More importantly, what can I do to make libc++ behave like libstdc++ does? That is to say, the getline function should not wait until the pipe buffer is full, it should immediately return a line of input as soon as it is available.

请参见下面的代码示例,该示例显示了我如何读取和写入管道.

See below for a code example that shows how I read from and write to pipes.

  • macOS 10.13.1(High Sierra)
  • Xcode 9.1
  • Apple LLVM版本9.0.0(clang-900.0.38)

我怀疑问题不仅限于macOS,但我还没有可用于测试的带有clang的Linux开发系统.

I suspect that the problem is not limited to macOS, but I haven't got a Linux dev system with clang that I can use to test.

打开三个壳,我们分别命名为A,B和C.

Open three shells, let's call them A, B and C.

在外壳A中:创建一个新文件pipe-test.cpp,然后从下面添加源代码.用libstdc++一次编译源代码,然后用libc++一次编译源代码:

In shell A: Create a new file pipe-test.cpp and add the source code from below. Compile the source code once with libstdc++ and once with libc++:

g++ -stdlib=libstdc++ -o pipe-test-libstdc++ pipe-test.cpp
g++ -stdlib=libc++ -o pipe-test-libc++ pipe-test.cpp

在外壳A中:创建两个管道:

In shell A: Create two pipes:

mkfifo input-pipe output-pipe

测试1,使用程序的libstdc++版本

  • 在外壳A中,运行以下命令:pipe-test-libstdc++ input-pipe output-pipe
  • 在外壳B中,运行以下命令:cat output-pipe
  • 在shell C中,运行以下命令:cat >input-pipe
  • 在外壳C中,键入"foo"行,然后按Enter
  • 切换到外壳B:您将看到字符串"foo".
  • 发生了什么事?在shell A中运行的程序已使用getline函数从输入管道读取了"foo"行,并立即将其打印到输出管道.
  • 在外壳C中,键入CTRL + D.测试到此结束,所有外壳程序现在都应该返回命令行.
  • Test 1, using the libstdc++ version of the program

    • In shell A, run this command: pipe-test-libstdc++ input-pipe output-pipe
    • In shell B, run this command: cat output-pipe
    • In shell C, run this command: cat >input-pipe
    • In shell C, type the line "foo" and press ENTER
    • Switch to shell B: You will see the string "foo".
    • What happened? The program that is running in shell A has read the line "foo" from the input pipe using the getline function and has immediately printed the line to the output pipe.
    • In shell C, type CTRL+D. This concludes the test, all shells should now be back on the command line.
      • 在外壳A中,运行以下命令:pipe-test-libc++ input-pipe output-pipe
      • 在外壳B中,运行以下命令:cat output-pipe
      • 在shell C中,运行以下命令:cat >input-pipe
      • 在外壳C中,键入"foo"行,然后按Enter
      • 切换到外壳B:您将看到字符串"foo".
      • 发生了什么事?在外壳A中运行的程序仍在阻塞,getline函数尚未从输入管道接收到"foo"行,因为该管道的缓冲区尚未满.
      • 在shell C中,键入CTRL + D.
      • 切换到外壳B:现在,您将看到字符串"foo".
      • 请注意,除了键入CTRL + D之外,您还可以将很多文本粘贴到外壳C中.一旦管道的缓冲区已满,getline函数将开始逐行读取输入,直到将其清空为止.管道的缓冲区.
      • In shell A, run this command: pipe-test-libc++ input-pipe output-pipe
      • In shell B, run this command: cat output-pipe
      • In shell C, run this command: cat >input-pipe
      • In shell C, type the line "foo" and press ENTER
      • Switch to shell B: You will NOT see the string "foo".
      • What happened? The program that is running in shell A is still blocking, the getline function has not yet received the line "foo" from the input pipe because that pipe's buffer is not yet full.
      • In shell C, type CTRL+D.
      • Switch to shell B: NOW you will see the string "foo".
      • Note that instead of typing CTRL+D you can also paste a lot of text into shell C. Once the pipe's buffer becomes full the getline function will start to read the input line-by-line until it has emptied the pipe's buffer.
      #include <string>
      #include <iostream>
      #include <fstream>
      
      
      int main(int argc, char** argv)
      {
        if (argc != 3)
        {
          std::cout
            << "Usage: pipe-test /path/to/input-pipe /path/to/output-pipe"
            << std::endl;
          return 1;
        }
      
        std::string pathToInputPipe = argv[1];
        std::string pathToOutputPipe = argv[2];
      
        std::cout
          << "Input pipe = " << pathToInputPipe << std::endl
          << "Output pipe = " << pathToOutputPipe << std::endl;
      
        std::ifstream inputPipeStream;
        inputPipeStream.open(pathToInputPipe.c_str());
        if (! inputPipeStream)
        {
          std::cout
            << "Failed to open input pipe " << pathToInputPipe
            << std::endl;
          return 1;
        }
        else
        {
          std::cout
            << "Input pipe: result of eof() = " << inputPipeStream.eof() << std::endl
            << "Input pipe: result of bad() = " << inputPipeStream.bad() << std::endl
            << "Input pipe: result of good() = " << inputPipeStream.good() << std::endl
            << "Input pipe: result of fail() = " << inputPipeStream.fail() << std::endl;
        }
      
        std::ofstream outputPipeStream;
        outputPipeStream.open(pathToOutputPipe.c_str());
        if (! outputPipeStream)
        {
          std::cout
            << "Failed to open output pipe " << pathToOutputPipe
            << std::endl;
          return 1;
        }
        else
        {
          std::cout
            << "Output pipe: result of eof() = " << outputPipeStream.eof() << std::endl
            << "Output pipe: result of bad() = " << outputPipeStream.bad() << std::endl
            << "Output pipe: result of good() = " << outputPipeStream.good() << std::endl
            << "Output pipe: result of fail() = " << outputPipeStream.fail() << std::endl;
        }
      
        int lineNumber = 0;
        while (true)
        {
          lineNumber++;
          std::string line;
          bool getlineFailResult = getline(inputPipeStream, line).fail();
          if (getlineFailResult)
          {
            std::cout << "Failed to read stream, stopping" << std::endl;
            break;
          }
          else
          {
            std::cout << "Received line " << lineNumber << ": " << line << std::endl;
            outputPipeStream << line << std::endl;
            outputPipeStream.flush();
          }
        }
      
        return 0;
      }
      

      推荐答案

      您可能已经知道,libc ++是标准库的非GPL(MIT)版本. libstdc ++是GPL版本. libc ++是LLVM的一部分. libstdc ++是通常随GCC一起提供的GPL库.

      As you are probably aware, the libc++ is a non-GPL (MIT) version of the standard library. libstdc++ is the GPL version. libc++ is part of LLVM. libstdc++ is a GPL library which usually ships with GCC.

      它们是两个完全不同的实现.哪种观点更好,或者应该使用哪种观点.例如,有许多线程:我应该使用libc ++还是libstdc ++?

      They are two entirely different implementations. Which one is better, or which one you should use is an opinion. There are a number of threads on this, for instance: Should I use libc++ or libstdc++?

      我无法在getline()上找到可以指定您关注的行为的规范.

      I could not readily find a spec on getline() which would specify the behavior you are concerned about.

      以下是libc ++版本中getline的源代码 https://github.com/llvm-mirror/libcxx/blob/018a3d51a47f7275c59e802709104498b729522b/include/istream#L1037

      Here is the source for getline in the libc++ version https://github.com/llvm-mirror/libcxx/blob/018a3d51a47f7275c59e802709104498b729522b/include/istream#L1037

      他们行为不同的事实并不令我感到惊讶.如果您需要getline()的特定实现/行为,我可以编写自己的代码(因为它不是一个复杂的操作),并使用标准的POSIX系统调用来做到这一点,并且应予以说明,并且应该相同-不管操作系统或编译器.

      The fact that they behave differently does not suprise me. If you need a specific implementation / behavior of getline() I would either write your own, as it's not a complex operation, and use standard POSIX system calls to do it which are spec'd out, and should be the same - regardless of OS or compiler.

      此外(在此处是个见解),我的建议是避免使用标准的C ++库(尤其是iostream)实现,除非它们已经存在于大型代码库中,并且您必须使用它们.它们充满错误,行为不同且通常不快.

      Also (opinion here), my advice is to avoid using the standard C++ libraries, especially iostream, implementation aside, unless they are already in a large code base and you must use them. They are full of errors, have differing behavior, and are generally not fast.

      这篇关于从管道读取时,为什么libc ++ getline会阻塞,而libstdc ++ getline却不会呢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆