一、reduction子句
reduction子句可以对一个或者多个参数指定一个操作符,然后每一个线程都会创建这个参数的私有拷贝,在并行区域结束后,迭代运行指定的运算符,并更新原参数的值。
私有拷贝变量的初始值依赖于redtution的运算类型。
具体用法如下
reduction(operator:list)
#include <stdio.h>
#include <omp.h>
int main(int argc, char* argv[])
{
int i, sum = 10;
#pragma omp parallel for reduction(+: sum)
for (i = 0; i < 10; i++)
{
sum += i;
printf("%d\n", sum);
}
printf("sum = %ld\n", sum);
return 0;
}
二、copyin子句
copyin子句可以将主线程中变量的值拷贝到各个线程的私有变量中,让各个线程可以访问主线程中的变量。
copyin的参数必须要被声明称threadprivate,对于类的话则并且带有明确的拷贝赋值操作符。
int g = 0;
#pragma omp threadprivate(g)
int main(int argc, char* argv[])
{
int i;
#pragma omp parallel for
for (i = 0; i < 4; i++)
{
g = omp_get_thread_num();
printf("thread %d, g = %d\n", omp_get_thread_num(), g);
}
printf("global g: %d\n", g);
#pragma omp parallel for copyin(g)
for (i = 0; i < 4; i++)
printf("thread %d, g = %d\n", omp_get_thread_num(), g);
return 0;
}
===== OUTPUT =====
thread 1, g = 1
thread 0, g = 0
thread 3, g = 3
thread 2, g = 2
global g: 0
thread 0, g = 0
thread 2, g = 0
thread 3, g = 0
thread 1, g = 0
三、schedule子句
OpenMP中的调度主要是指如何将任务分配给各个线程。主要有static和dynamic两种。
1. static方式
在不指定调度方式的情形下,默认采用static方式。static方式是这样的,假设有n次循环迭代,t个线程,那么每个线程大约分到n/t次迭代。这种调度方式会将循环迭代均匀的分布给各个线程,各个线程迭代次数可能相差1次。示例见下
int i;
#pragma omp parallel for schedule(static)
for (i = 0; i < 10; i++)
{
printf("i = %d, thread %d\n", i, omp_get_thread_num());
}
在静态调度的时候,我们可以通过指定size参数来分配一个线程的最小迭代次数。换句话说,我们通过size参数可以指定一个线程的最小并行任务数。
int i;
#pragma omp parallel for schedule(static, 3)
for (i = 0; i < 4; i++)
{
printf("i = %d, thread %d\n", i, omp_get_thread_num());
}
===== OUTPUT =====
i = 3, thread 1
i = 0, thread 0
i = 1, thread 0
i = 2, thread 0
2. dynamic方式
动态分配是将迭代动态分配到各个线程,依赖于运行你状态来确定,所以我们无法像静态调度一样事先预计进程的分配。哪一个线程先启动,哪一个线程迭代多久,这些都取决于系统的资源和线程的调度。
int i;
#pragma omp parallel for schedule(dynamic)
for (i = 0; i < 10; i++)
{
printf("i = %d, thread %d\n", i, omp_get_thread_num());
}