OpenMP - 并行代码有意想不到的结果

时间:2013-01-24 10:23:32

标签: c++ parallel-processing openmp

#include "/usr/lib/gcc/i686-linux-gnu/4.6/include/omp.h"
#include <iostream>
#include<list>
using namespace std;

int main()
{
    list<int> lst;
    for(int i=0;i<5;i++)
        lst.push_back(i);

#pragma omp parallel for
    for(int i=0;i<5;i++)
    {
        cout<<i<<" "<<omp_get_thread_num()<<endl;
    }   
}

假设我能得到这个:

0  0
1  0
2  0
3  1
4  1

然而,有时我可以得到这个结果:

30  0
1  0
2  0
  1
4  1

甚至是这种结果:

30 1 0
4 1

1 0
2 0

我知道这是因为输出代码:

cout<<i<<" "<<omp_get_thread_num()<<endl;

已拼接成小段,在输出时没有顺序。 但谁能告诉我如何防止这种情况发生? 感谢。

4 个答案:

答案 0 :(得分:3)

标准输出流未同步!

标准给出的唯一保证是,单个字符以原子方式输出。

你需要一个锁定 - 它会违反并行化点,或者你可以删除“&lt;&lt; i”,这将导致准同步行为。

答案 1 :(得分:1)

循环乱序。这就是你输出无序的原因。

如果您的问题是<{p>}中的30

30  0
1  0
2  0
 1
4  1

然后保持冷静,没有30,但30。正如预期的那样,您仍然有一行无序的[0..4]

3 0  0
1  0
2  0
 1
4  1

你不能告诉的是0中哪个1 s不是一个主题号。

答案 2 :(得分:0)

您可以创建一个数组(大小为5),其中包含哪个线程处理了哪个索引,然后将其打印到并行循环之外。

答案 3 :(得分:0)

您的代码

#pragma omp parallel for
    for(int i = 0; i < 5; i++)
    {
        cout << i << " " << omp_get_thread_num() << endl;
    }

相当于

#pragma omp parallel for
    for(int i = 0; i < 5; i++)
    {
        cout << i;
        cout << " ";
        cout << omp_get_thread_num();
        cout << endl;
    }

可以按任何顺序执行对不同线程中的<<的调用。例如,线程3中的cout << i;在脚本0后面可能跟cout << i;,后面可能跟在线程3中的cout << " ";等,导致输出为30 ...

正确的方法是重写代码,以便每个线程只在循环中调用cout <<一次:

#pragma omp parallel for
    for(int i = 0; i < 5; i++)
    {
        stringstream ss;
        ss << i << " " << omp_get_thread_num() << '\n';
        cout << ss.str();
    }   
相关问题