【问题标题】:How does std::ios_base::sync_with_stdio impact stream buffering?std::ios_base::sync_with_stdio 如何影响流缓冲?
【发布时间】:2018-08-20 15:54:12
【问题描述】:

Stack Overflow 上的this answercppreference.com 都建议关闭流同步以提高性能,认为流同步会禁用缓冲。

现在这是我不明白的。为什么同步流不能简单地共享缓冲区?我想象如果流是同步的,std::fputc(stdout, c); 可以简单地以std::cout << c; 或相反的方式(或使用通用原语)来实现。因此,当 C I/O 与 C++ I/O 混合时,同步流甚至比非同步流更有优势!更少的缓冲区,更少的缓存未命中。

当前的 C++ 标准草案似乎与我同在。在指定sync_with_stdio() 的脚注中,它说“实际上,同步通常意味着标准iostream 对象和标准stdio 对象共享一个缓冲区。”我在上面发布的链接是否可能只是记录了一些不完善的实现及其对性能的影响?

另外,因为我没有看到非同步流的任何理论上的缺点,我想知道为什么这些首先存在。

【问题讨论】:

  • 附带说明,cppreference 建议sync_with_stdio() 影响标准流的线程安全。我认为这是完全错误的。
  • std::streambuf 和支持stdio 的任何缓冲区不能相同(它们具有不同的接口)。因此,根据我对链接的阅读,std::streambuf 实现输出到 stdio 缓冲区,而本身不做任何缓冲。所以他们确实共享一个缓冲区,但 iostreams 有一个额外的间接层来获取它。此外,它们必须具有额外的线程锁定,以便通过 stdio 操作保持线程安全。
  • 我不太明白。同步与否,两者共享同一个设备,必须始终相互独占访问。因此,一个同时保护 cin 和 stdin 的互斥体就足够了,不是吗?
  • 好吧,C++ 无法访问终极设备,这是 shell 的责任。但即便如此,在您到达设备之前,您拥有共享缓冲区,该缓冲区需要 stdio 和 iostream 之间的互斥体。我想他们可以为此共享一个互斥锁,但这会将两个库非常紧密地耦合在一起,我不知道那里有什么恶魔。无论如何,我认为 iostream 可能必须拥有自己的独立锁定才能在所有 streams 中履行其线程安全义务,而不仅仅是cin/cout。所以我怀疑它必须锁定 两个 互斥锁才能与 stdio 同步。
  • @purefanatic sync_with_stdio() 会影响eel.is/c++draft/iostream.objects#overview-5 中指定的标准流的线程安全

标签: c++ iostream


【解决方案1】:

std::fputc(stdout, c); 可以简单地以std::cout << c; 或相反的方式实现(或使用通用原语)

实际上是“反其道而行之”。同步的std::cout是一个无缓冲的流,每个std::cout << c;立即执行std::fputc(stdout, c);

同步流甚至比非同步流更有优势!更少的缓冲区,更少的缓存未命中

无论哪种方式,它都只是一个缓冲区:stdout 同步时或 std::cout 不同步时。在我的 gcc/libstdc++ 上,主要区别是一个是 1024 字节,另一个是 8191(严重)。分析标准库的三个现有实现(libstdc++、libc++ 和 MSVC)以发现差异以及造成差异的原因可能会很有趣。很可能它们是“不完美的实现”——没有理由不同步的std::cout << c; 应该比(总是同步的)std::fputc(stdout, c); 慢。

【讨论】:

  • "每个 std::cout synchronized I/O 应该没有理由比 unsynchronized I/O 慢!
  • 是的,C I/O 使用标准输出的缓冲区。我的意思是“对于 C++ I/O”,无论哪种方式都有一个缓冲区。至于速度慢,同步会产生互斥锁的成本。这就是为什么 C I/O 通常带有不可移植的非同步 API,例如 GNU putchar_unlocked
  • 8191 还是8192?定义为BUFSIZ(注意:Nix 上的8192 和Windows 上的512)gcc 源代码中的基本宏是_IO_BUFSIZ
  • @DavidC.Rankin 是的,stdio_filebuf 说它使用 BUFSIZ,但是当我使用 strace 运行时,我看到大小为 8191 的 write() 调用
  • 上帝知道多余的字节在哪里,毫无疑问它在源代码中定义为8192。 -- 如果这是我一天中唯一丢失的字节 -- 这是美好的一天。
【解决方案2】:

我推荐阅读一个完美的答案here。根据最初由 Ionut 编写的答案,“如果禁用同步,则允许 C++ 流拥有自己的独立缓冲区”。这本书也讨论了here,我想在第 11 章。

【讨论】:

    猜你喜欢
    • 2018-01-11
    • 2022-01-15
    • 1970-01-01
    • 2022-01-15
    • 2016-02-23
    • 2015-09-18
    • 2021-07-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多