使用OpenMP获得完整,完整的输出需要什么?

时间:2018-07-31 04:56:39

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

我有一些根据c ++ 11标准编译的代码。我有多个线程写入cout。我注意到在编写多行时,有些情况下会缺少某些行(例如2000000中的1)。我很惊讶地看到这一点,因为我的字符串(下面的{outStr)对于每个线程都是本地的,并且在对stdout的写操作中有一个关键部分。我注意到当我冲洗流时问题就消失了。

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

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

总体而言,总体而言,我对关键部分并不满意,因为我注意到剖析会引起很多争执。我愿意提出任何改善我的I / O的建议。

* Edit我给人的印象是,在c ++ 11下,只要我同步输出(即使用关键部分时就不会出现交错或丢失输出),输出就不会受到破坏,但是似乎缺少行表示这还不能保证不刷新输出就可以保证。

2 个答案:

答案 0 :(得分:3)

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

预防该问题的最明显方法可能是使流本身归一个线程所有,并具有需要将其写入流的线程安全队列。如果您可以累积一个“大块”数据以将数据流放入字符串(或其他一些预定的数据结构)中,那么这很简单。

我要记录一下,虽然您最终可能希望使用无锁队列,但是基于锁的相当简单,老式的队列几乎仍然可以肯定会提供巨大的改进相对于您现在正在执行的操作而言,将字符串插入队列要比刷新流明显快得多(在纳秒到几微秒的范围内,刷新通常约为毫秒)。

答案 1 :(得分:0)

似乎是罪魁祸首std::cout.sync_with_stdio(false);。我没想到这是问题,但是在我做了一个简单的测试程序后我注意到了。我曾尝试使用该功能来加快I / O的速度,但事实证明这不是一个好主意。

尽管在关键部分中,但I / O流似乎不是线程安全的。我也没有在代码中使用任何printf

根据documentation

  

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

似乎由于某些原因,如果不同步缓冲区,缓冲区将决定以随机间隔刷新。

删除后,我实际上可以通过一个简单的`cout << outStr;获得一致的输出。语句不刷新。另外,我仍在进行测试,看来我可能根本不需要关键部分。