OpenMP中的线程时并发执行的,即不同线程时乱序执行的,有时需要并发线程来协调线程组的执行,达到约束线程组之间某些操作的顺序。
此处还是通过前文【OpenMP】 2.1 简单示例-CSDN博客的例程进行说明。
1 、临界区(critical)
临界区critical构造定义了一个线程间相互排斥的代码块,即并行构造中一次只能有一个线程执行临界区中的代码块,其余的线程在critical构造处等待,直到之前的线程完成后依次运行。
#include <stdio.h>
#include <omp.h>
#define NTHREADS 4
static long num_steps = 1e9;
double step;
int main() {
int i, nthreads;
double pi, full_sum = 0.0;
double start_time, run_time;
step = 1.0 / (double) num_steps;
full_sum = 0.0;
omp_set_num_threads(NTHREADS);
start_time = omp_get_wtime();
#pragma omp parallel default(shared)
{
int i, id = omp_get_thread_num();
int numthreads = omp_get_num_threads();
//创建局部变量x、partial_sum,仅在当前线程内可见
double x, partial_sum = 0;
//获取真实线程
if (id == 0)
nthreads = numthreads;
for (i = id; i < num_steps; i += numthreads) {
x = (i + 0.5) * step;
partial_sum += 4.0 / (1.0 + x * x);
}
// 一次只能有一个线程运行下述代码块,其余线程在此处等待
// 如果构造中没有添加大括号{},则并行区域只有构造下的一条语句
#pragma omp critical
full_sum += partial_sum;
} // end of parallel region
pi = step * full_sum;
run_time = omp_get_wtime() - start_time;
printf("\n pi \%f in \%f secs \%d threds \n ",
pi, run_time, nthreads);
}
pi 3.141593 in 0.848268 secs 4 threds
Process finished with exit code 0
上述示例中通过临界区实现的积分计算,且每个线程只执行一次临界区中的代码;需要注意的是如果并行区域内的代码是频繁遇见critical临界区,将会浪费大量的时间在临界区钱的等待过程中,影响并行性能。
2、栅栏(barrier)
栅栏可以看做是另一个并行同步指令(与OpenMP构造不同的是它不与结构化的代码块相关联),与临界区不同的是,栅栏是在并行代码段中定义了一个线程间的同步点,即所有线程都要运行到这个点处,程序才可以继续往下进行,否则线程在栅栏构造处等待。
#include <iostream>
#include <omp.h>
#define NTHREADS 4
double needs_all_of_Arr(int id, int nthrds, const double Arr[]) {
double result = 0.;
for (int i = 0; i < nthrds; ++i) {
result += Arr[i];
}
return result / id;
}
int main() {
double Arr[NTHREADS], Brr[NTHREADS];
int numthrds;
omp_set_num_threads(NTHREADS);
#pragma omp parallel
{
int id, nthrds;
id = omp_get_thread_num();
nthrds = omp_get_num_threads();
if (id == 0) numthrds = nthrds;
Arr[id] = id;
//所有线程都要运行到此处后才可以继续往下执行
#pragma omp barrier
Brr[id] = needs_all_of_Arr(id, nthrds, Arr);
#pragma omp critical
std::cout << "当前ID:" << id << "数值 " << Brr[id] << std::endl;
} // end of parallel region
}
当前ID:2数值 3
当前ID:1数值 6
当前ID:0数值 inf
当前ID:3数值 2
Process finished with exit code 0