并行计算 - 输出混乱?

R. *_*der 6 c c++ parallel-processing openmp

我正在尝试学习并行计算的基础知识,但我在计算机上遇到了一个问题.看看下面的代码.基本上,我想打印出"Hello World!"这一行.我的电脑拥有的每一个核心.我的电脑有四个核心,因此它应打印出该行四次.如果我使用注释掉的'cout'行而不是'printf'行,输出将全部混乱.这是因为'\n'转义命令与"Hello World!"分开执行,因此新行输出将随机发生.'printf'行是这个问题的解决方案,因为该行是一次性执行的(不会分成像'cout'行这样的部分).但是,当我使用'printf'时,我的输出仍然混乱,好像我使用'cout'.我不知道为什么会这样做.我在另一台计算机上尝试了完全相同的代码,它完美无缺.只有我的电脑继续用'printf'混淆输出.我已经通过电子邮件向我的CS教授发了电子邮件,他不知道为什么要在我的电脑上这样做.我知道我在计算机上正确设置了OpenMP.有并行计算经验的人是否知道为什么这会弄乱我的电脑?

#include <omp.h>
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
using namespace std;

int main()
{
    #pragma omp parallel
    {
        printf("Hello World!\n");
        //cout << "Hello World!\n" << endl;
    }
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

为了显示我正在谈论的内容,这是我在计算机上运行上述代码时的输出:

你好禾

你好,世界!

RLD!

你好,世界!

Bri*_*ain 7

对不起,你的教授错了.您需要利用互斥或其他障碍,以保证不间断使用共享资源(在本例中是STDOUT输出文件).

混合输出是潜在的预期行为,无论是printfstd::cout::operator<<().由于设计的不同,您看到的行为差异是每个行为的执行持续时间的细微差别.在任何一种情况下都应该期待这种行为.

我只是不明白为什么它会为其他人工作.

不是.成为班上的英雄并解释它是如何工作的以及如何解决它.告诉他们SO发送他们的爱.:)


Gil*_*les 5

正如已经解释过的那样,假设printf()是原子的并且不会破坏你的输出而std::cout::operator<<()不是并且如果从根本上错误就会搞砸.

然而,在这方面仍有一小部分"真相",但处于不同的层面.让我给你举个例子:

如果我尝试OpenMP"Hello world"C风格,那可能会给出:

printf( "Hello from thread %d of %d\n",
         omp_get_thread_num(),
         omp_get_num_threads() );
Run Code Online (Sandbox Code Playgroud)

同样的C++风格可能如下所示:

std::cout << "Hello from thread " << omp_get_thread_num()
          << " of " << omp_get_num_threads()
          << std::endl;
Run Code Online (Sandbox Code Playgroud)

两者之间的本质区别在于printf(),我只用一个完全准备好的输出字符串调用一次打印方法,而C++风格的输出字符串将调用std::cout::operator<<()5次,只有一些点可以是或不是发送到标准输出.在内部,任何事情都可能发生,我不会尝试任何形式的行为.但至少通过printf()在这里使用,我增加了输出清洁的机会,即使我无法保证它.

这是一个完整的例子:

#include <iostream>
#include <stdio.h>
#include <omp.h>

int main() {
    #pragma omp parallel
    printf( "Hello from thread %d of %d with printf()\n",
             omp_get_thread_num(),
             omp_get_num_threads() );

    printf( "*** outside of parallel region ***\n" );

    #pragma omp parallel
    std::cout << "Hello from thread " << omp_get_thread_num()
              << " of " << omp_get_num_threads()
              << " with std::cout"
              << std::endl;
    return 0;
}
Run Code Online (Sandbox Code Playgroud)

在我的Linux笔记本电脑上给我(GCC 5.2):

~/tmp$ g++ -fopenmp stdout.cc
~/tmp$ ./a.out 
Hello from thread 3 of 4 with printf()
Hello from thread 0 of 4 with printf()
Hello from thread 2 of 4 with printf()
Hello from thread 1 of 4 with printf()
*** outside of parallel region ***
Hello from thread Hello from thread Hello from thread Hello from thread 1 of 4 with std::cout23 of 4 with std::cout
 of 4 with std::cout
0 of 4 with std::cout

~/tmp$
Run Code Online (Sandbox Code Playgroud)

如果你仔细观察,你可以看到没有任何一个单独的调用std::cout::operator<<()被拆分,但是每个新的调用都是各个线程相互竞争的机会,并且会使输出受损.

再说一次,告诉它printf()是原子的并且不会搞砸是错误的,但简单地说,对于复杂的输出字符串,它不太可能被破坏std::cout.