并行计算——混淆了输出?

Parallel computing -- jumbled up output?

我正在尝试学习并行计算的基础知识,但我 运行 在我的计算机上遇到了问题。看看下面我的代码。基本上,我想打印出“Hello World!”这一行。对于我的计算机的每个核心。我的电脑有四个核心,所以它应该打印四次该行。如果我使用注释掉的 'cout' 行而不是 'printf' 行,输出将全部混乱。这是因为 '\n' 转义命令与 "Hello World!" 分开执行,所以换行输出会 运行domly 发生。 '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;
}

为了说明我在说什么,下面是我在计算机上 运行 上述代码时的输出:

Hello Wo

Hello World!

rld!

Hello World!

抱歉,您的教授弄错了。您需要利用互斥或其他一些障碍来保证不间断地使用共享资源(在本例中是 STDOUT 输出文件)。

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

I just don't understand why it would be working for everyone else.

不是。成为您 class 的英雄并解释它的工作原理和修复方法。告诉他们 SO 发送他们的爱。 :)

如前所述,假设 printf() 是原子的,不会破坏您的输出,而 std::cout::operator<<() 不是,如果从根本上是错误的,将会把事情搞砸。

不过,这里面还有"truth"的(微小的)一部分,只是层次不同而已。让我举个例子:

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

printf( "Hello from thread %d of %d\n",
         omp_get_thread_num(),
         omp_get_num_threads() );

同一个 C++ 风格可能如下所示:

std::cout << "Hello from thread " << omp_get_thread_num()
          << " of " << omp_get_num_threads()
          << std::endl;

两者的本质区别在于,对于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;
}

我的 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$

如果你仔细观察,你会发现 none 对 std::cout::operator<<() 的单独调用是分开的,但每个新调用都是不同线程相互竞争的机会,并且使输出混乱。

所以再说一遍,说 printf() 是原子的并且不会把事情搞砸是错误的,但简单地说,对于一个复杂的输出字符串,它比 std::cout 更不容易被破坏.