C++ OpenMP-仅创建一次线程

C++ OpenMP-仅创建一次线程,c++,openmp,C++,Openmp,我尝试使用OpenMP编写简单的应用程序。不幸的是,我对加速有问题。 在这个应用程序中,我有一个while循环。这个循环的主体由一些应该按顺序执行的指令和一个用于循环的指令组成。我使用#pragma omp parallel for使这个for循环并行。这个循环没有太多工作,但是经常被调用 我准备了两个版本的for循环,并在1、2和4个核心上运行应用程序。 版本1(for循环中的4次迭代):22秒、23秒、26秒。 版本2(for循环中100000次迭代):20秒,10秒,6秒 如您所见,当fo

我尝试使用OpenMP编写简单的应用程序。不幸的是,我对加速有问题。 在这个应用程序中,我有一个while循环。这个循环的主体由一些应该按顺序执行的指令和一个用于循环的指令组成。我使用
#pragma omp parallel for
使这个for循环并行。这个循环没有太多工作,但是经常被调用

我准备了两个版本的for循环,并在1、2和4个核心上运行应用程序。
版本1(for循环中的4次迭代):22秒、23秒、26秒。
版本2(for循环中100000次迭代):20秒,10秒,6秒

如您所见,当for循环没有太多工作时,2核和4核上的时间比1核上的时间要长。 我猜原因是
#pragma omp parallel for
在while循环的每次迭代中都会创建新线程。所以,我想问你们——是否有可能创建一次线程(在while循环之前),并确保while循环中的某些工作将按顺序完成

#include <omp.h>
#include <iostream>
#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <time.h>
int main(int argc, char* argv[])
{
    double sum = 0;
    while (true)
    {
        // ...
        // some work which should be done sequentially
        // ...

        #pragma omp parallel for num_threads(atoi(argv[1])) reduction(+:sum)
        for(int j=0; j<4; ++j)  // version 2: for(int j=0; j<100000; ++j)
        {
            double x = pow(j, 3.0);
            x = sqrt(x);
            x = sin(x);
            x = cos(x);
            x = tan(x);
            sum += x;

            double y = pow(j, 3.0);
            y = sqrt(y);
            y = sin(y);
            y = cos(y);
            y = tan(y);
            sum += y;

            double z = pow(j, 3.0);
            z = sqrt(z);
            z = sin(z);
            z = cos(z);
            z = tan(z);
            sum += z;
        }

        if (sum > 100000000)
        {
            break;
        }
    }
    return 0;
}
#包括
#包括
#包括
#包括
#包括
#包括
int main(int argc,char*argv[])
{
双和=0;
while(true)
{
// ...
//一些应该按顺序进行的工作
// ...
#用于num_线程(atoi(argv[1])缩减(+:sum)的pragma omp并行

对于(int j=0;j您可以将并行区域移到
while(true)
循环之外,并使用
single
指令使代码的串行部分仅在一个线程中执行。这将消除fork/join模型的开销。此外,OpenMP在迭代次数非常少的thight循环中也不太有用(就像你的版本1)。你基本上是在测量OpenMP开销,因为循环中的工作完成得非常快——即使是使用超越函数的100000次迭代,在当前一代CPU上也只需要不到一秒钟的时间(在2 GHz的频率下,每个FP指令大约需要100个周期,除了加法,它需要约100毫秒)

这就是为什么OpenMP提供了
if(condition)
子句,可用于有选择地关闭小循环的并行化:

#omp parallel for ... if(loopcnt > 10000)
for (i = 0; i < loopcnt; i++)
   ...
#用于…if的omp并行(loopcnt>10000)
对于(i=0;i

对于常规循环(即每次迭代的计算时间大致相同的循环),建议使用
调度(静态)
d适用于OpenMP的常见用例


当你增加OpenMP线程的数量时,你看到的减速很可能是由于在一个循环上施加了少量迭代的并行开销。Hristo的回答涵盖了这一点。

我对这个主题不太熟悉,但在他的OpenMP在线课程中,Tim Mattson几次非常明确地说广告是在
#pragma omp parallel
创建的,并在块的末尾连接。因此,这似乎与您的答案相矛盾。