首页 > 解决方案 > 在 std::cin 上累积积压会导致它丢失数据

问题描述

我有一个外部二进制文件,它向标准输出产生无限的二进制数据流(~10 MiB/s),我正在尝试编写一个 C++ 程序来使用它。我的消费者程序有一个不寻常的模式:它首先从流中读取少量数据(~32KiB),处理大约一分钟,然后以更快的速度(> 50 MiB/s)再次开始消费数据.

我正在调用该程序,如下所示:$ my_producer | my_consumer.

因为消费者最初比消费者慢得多,所以我预计管道会积压约60s * 10 MiB/s = 600 MiB. 然而,在一分钟的初始延迟之后,我的消费者开始以大约 10MiB/s 的速度消费数据,这意味着在一分钟间隔内产生的数据丢失了;为什么?

消费者的相关代码是这样的:

std::vector<char> StreamSource::Read(std::size_t size) {
  auto data = std::vector<char>(size);
  stream_.read(data.data(), size);
  data.resize(stream_.gcount());
  assert(stream_.good() || stream_.eof());
  return data;
}

std::istream& stream_;  // Initialized to std::cin

有趣的是,写入文件然后将该文件传递给消费者可以按预期工作!

$ my_producer > ~/Desktop/data
$ cat ~/Desktop/data | my_consumer

我进行了一系列测试,以确保我的制片人不会受到责备;以下失败,因为生产者检测到“短写”:

$ my_producer | throttle -M1 > ~/Desktop/data

我正在寻找有关如何解释丢失数据的建议。如果它是相关的,我在 MacOS 上运行。

谢谢!

标签: c++linuxunixpipe

解决方案


我很确定没有操作系统允许管道建立到 600mb,当管道满时写入端将阻塞。如果你想允许建立这么多数据,你需要在你的应用程序中有一个线程cin连续读取并缓冲数据,然后你的应用程序可以从该缓冲区读取,而不是从cin.

根据https://unix.stackexchange.com/questions/11946/how-big-is-the-pipe-buffer,管道通常最大为 64K。


推荐阅读