#pragma omp parallel:
将创建一个包含threads 团队的parallel region,其中每个线程将执行parallel region 所包含的整个代码块。
从OpenMP 5.1 可以阅读更正式的描述:
当一个线程遇到一个并行结构时,一组线程被
创建 来执行并行区域 (..)。这
遇到并行构造的线程成为主线程
新团队的线程,持续时间的线程数为零
新的平行区域。 新团队中的所有主题,包括
主线程,执行区域。 创建团队后,
团队中的线程数在持续时间内保持不变
那个平行区域。
:
#pragma omp parallel for
将创建一个parallel region(如前所述),并使用default chunk size和default schedule为该区域的threads分配它所包含的循环的迭代,即通常 static。但是请记住,default schedule 在 OpenMP 标准的不同具体实现之间可能会有所不同。
您可以从OpenMP 5.1 阅读更正式的描述:
worksharing-loop 结构指定一个或一个的迭代
更多相关的循环将由线程中的线程并行执行
团队在他们的隐含任务的背景下。 迭代是
分布在团队中已经存在的线程中
执行工作共享循环区域所在的并行区域
绑定。
Moreover,
并行循环结构是指定并行循环的快捷方式
包含带有一个或多个相关联的循环构造的构造
循环,没有其他语句。
或者非正式地,#pragma omp parallel for 是构造函数#pragma omp parallel 和#pragma omp for 的组合。在您的情况下,这意味着:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
在语义上和逻辑上与:
#pragma omp parallel
{
#pragma omp for
for(int i=0;i<n;i++)
{
c[i]=a[i]+b[i];
}
}
TL;DR:在您的示例中,使用#pragma omp parallel for,循环将在线程之间并行化(即循环迭代将在线程之间划分),而#pragma omp parallel 所有线程将执行(并行)所有循环迭代。
为了更便于说明,使用4 线程和#pragma omp parallel,会产生如下结果:
而 #pragma omp parallel for 与 chunk_size=1 和 static schedule 会导致类似:
在代码方面,循环将被转换为逻辑上类似于:
for(int i=omp_get_thread_num(); i < n; i+=omp_get_num_threads())
{
c[i]=a[i]+b[i];
}
在哪里omp_get_thread_num()
omp_get_thread_num 例程返回线程号,在
调用线程的当前团队。
和omp_get_num_threads()
返回当前团队中的线程数。在一个顺序
程序 omp_get_num_threads 的部分返回 1。
或者换句话说,for(int i = THREAD_ID; i < n; i += TOTAL_THREADS)。其中THREAD_ID 范围从0 到TOTAL_THREADS - 1,TOTAL_THREADS 表示在并行区域上创建的团队的线程总数。
我了解到我们需要使用 #pragma omp parallel for while
在 for 循环中使用 OpenMP。 但我也尝试过同样的事情
使用#pragma omp parallel,它也给了我正确的输出。
它为您提供相同的输出,因为在您的代码中:
c[i]=a[i]+b[i];
数组a和数组b是只读的,数组c[i]是唯一被更新的,它的值不取决于迭代i会执行多少次。尽管如此,使用#pragma omp parallel for,每个线程都会更新自己的i,而使用#pragma omp parallel,线程将更新相同的is,因此会覆盖彼此的值。
现在尝试用下面的代码做同样的事情:
#pragma omp parallel for
{
for(int i=0;i<n;i++)
{
c[i]= c[i] + a[i] + b[i];
}
}
和
#pragma omp for
{
for(int i=0;i<n;i++)
{
c[i] = c[i] + a[i] + b[i];
}
}
您会立即注意到不同之处。