【问题标题】:What is needed to get complete, uncorrupted output with OpenMP?使用 OpenMP 获得完整、未损坏的输出需要什么?
【发布时间】:2019-01-07 09:30:27
【问题描述】:

我有一些在 c++11 标准下编译的代码。我有多个线程写入 cout。我注意到在写很多行时,会有一些行丢失的情况(比如 2000000 行中有 1 行)。我很惊讶地看到这一点,因为我的字符串(下面的outStr)对于每个线程都是本地的,而且我在写入标准输出时有一个关键部分。当我刷新流时,我注意到问题消失了。

#pragma omp critical(cout)
{
    cout << outStr;
    cout.flush();
}

这是预期的行为吗?真正欺骗我的是,当我写的行数相对较少(

总的来说,我对关键部分并不满意,因为我在分析中注意到它引起了很多争论。我愿意接受任何改进我的 I/O 的建议。

*编辑我的印象是,在 c++11 下,只要我同步我的输出(即当我使用关键部分时没有交错或丢失输出),我的输出就不会损坏,但似乎缺少的行表示如果不刷新输出,这不是保证。

【问题讨论】:

  • 我不知道消失的行有什么问题,但我会写入单独的文件并在运行结束时将它们合并。
  • @n.m.如果这是管道的一部分,那么能够在不先写入磁盘的情况下写入标准输出是很好的。
  • @john 另一个问题没有提到仅在输出同步时才需要刷新。如果 c++11 中的 cout 是线程安全的,它是相似的,但没有解决为什么我的输出中会丢失一些字符串。
  • 我同意,如果我们只看问题的“标题”,另一个可能是重复的,但实际上这两个问题确实完全不同。我已经编辑了这个标题,以更准确地反映我认为这个问题的真正意图。
  • 另一种方法是使用单个专用写入器和一些无锁队列将消息从工作器传递到写入器。

标签: c++ c++11 openmp cout flush


【解决方案1】:

看来std::cout.sync_with_stdio(false); 是罪魁祸首。我没想到这是问题,但在我制作了一个简单的测试程序后我注意到了它。我曾使用该函数来加速我的 I/O,结果证明这是个坏主意。

看起来,虽然在关键部分,I/O 流不是线程安全的。我的代码中也没有使用任何printfs。

根据documentation

此外,同步的 C++ 流保证是线程安全的(从多个线程输出的单个字符可能交错,但不会发生数据竞争)

似乎不同步缓冲区会出于某种原因决定以随机间隔刷新。

删除这个之后,我实际上能够通过简单的 `cout 不刷新。另外,我还在做测试,看来我可能根本不需要关键部分。

【讨论】:

    【解决方案2】:

    这里的大部分问题源于刷新流相当缓慢的事实。因此,当一个线程进入临界区时,它们会在其中停留相当长的一段时间。到他们完成时,可能还有其他几个线程在等待,所以它成为一个严重的瓶颈。

    防止该问题的最明显方法可能是让流本身由一个线程拥有,并拥有一个线程安全的队列,其中包含需要写入流的事物。如果您可以累积“块”数据以将流转换为字符串(或其他一些预先确定的数据结构),那么这甚至是微不足道的。

    我要郑重说明,虽然您最终可能希望使用无锁队列,但基于锁定的相当简单、老式的队列几乎肯定会提供巨大的改进在你现在正在做的事情上——将字符串插入队列大大比刷新流快(在纳秒到可能几微秒的范围内,其中刷新通常大约为毫秒)。

    【讨论】:

    • 出于好奇,你知道为什么需要刷新来保留输出吗?考虑到输出在小型测试用例中看起来几乎正确,这真是一件令人讨厌的事情。
    • 没有。缺乏刷新允许来自不同线程的输出任意交错,但这应该是全部。我怀疑您在使用的标准库实现中发现了一个错误,但我们需要非常小心地检查代码和输出,以确定是否是这种情况。如果您愿意,您可以尝试我在another answer 中发布的同步流和事务类。我不确定它是否会有所帮助,但它可能会。
    • 很奇怪。我正在使用 gcc 版本 5.5.0。我已经确认我确实缺少应该在没有刷新的情况下输出的字符。我应该补充一点,我也会在程序的最后进行刷新。
    • 如果是这样,在我看来,这听起来确实像是一个错误。
    • 在我从代码中删除 std::cout.sync_with_stdio(false); 后问题似乎消失了,这很奇怪,因为我的代码中没有使用任何 printf
    猜你喜欢
    • 2018-01-27
    • 1970-01-01
    • 2015-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多