首页 > 解决方案 > 使用 OpenMP 获得完整、未损坏的输出需要什么?

问题描述

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

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

这是预期的行为吗?真正欺骗我的是,当我写的行数相对较少(<100000)时,我总是会看到输出的预期行数。

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

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

标签: c++c++11openmpcoutflush

解决方案


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

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

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


推荐阅读