c++ OMP 入门(HPC高性能计算第一节)

背景(Open Multi-Processing)

OMP是一套跨平台共享内存多线程并发编程API,目的是提高计算速度

API接口

### 头文件

#include <omp.h>

### 常用API接口

 

#pragma omp parallel num_threads(4) default(none) shared(data,std::cout)

 启动四个线程,default(none)要求所有变量都要显示指定

 data变量所有线程均可访问

 std::cout实际上是一个全局变量,所以需要显示指定,如果在其他情况下,需要用#pragma omp critical来加锁,该变量只能由一个线程访问

 #pragma omp single

 表示只需要一个线程执行以下语句

 #pragma omp barrier

 表示所有线程都执行完该命令后,才继续执行

 #pragma omp sections

 表示多个线程可以同时执行,但是需要等待所有线程都执行完才继续执行

 #pragma omp section

 表示以下不同代码块会被分配不同的线程

 #pragma omp critical(A)

 表示A锁,不指定锁命默认critical使用同一把锁

omp_get_wtime()

返回lf时间

omp_get_thread_num()

获得线程id

 

 omp_set_nested(1)

 启动多层嵌套,内外多线程,嵌套并行

pragma omp parallel for 

OpenMP 中用于 并行循环 的指令。它可以让多个线程自动分配循环迭代任务,加速代码执行。

错误示范:

int parallel_worng_arraysum(){
    int sum = 0;
    int a[10] = {1,2,3,4,5,6,7,8,9,10};
#pragma omp parallel for
    for (int i=0;i<10;i++)
        sum = sum + a[i];
    return sum;
}

`sum` 的更新在并行环境下导致数据竞争,因为多个线程可能会同时更新 `sum`。故该方法并不安全

修改方法

 #pragma omp parallel for reduction(+:sum)

使用该方法课加法规约优化

 #pragma omp for nowait

该 `for` 循环结束后,不需要强制执行线程的隐式同步。意味着某一线程完成任务后可执行其他任务

#pragma omp ordered

#pragma omp parallel for schedule(dynamic)

 动态调度(dynamic)

任务分配方式:每个线程先分配一部分循环迭代任务,执行完后再领取新任务,直到所有任务完成。

适用场景:

每次循环的计算量不均匀(比如有些任务很重,有些任务很轻)。

适用于 不确定的计算任务,比如数据依赖或分支跳转的计算。

// sections 后面存在隐藏同步点
#pragma omp sections nowait

#pragma omp sections后的代码会等待所有section完成之后才执行,如果加入nowait,则每个线程完成section部分后会直接运行second之后的代码

示例:

#include <omp.h>
#include <stdio.h>
#include <unistd.h>
 
int main()
{
#pragma omp parallel num_threads(4) default(none)
   {
// sections 后面存在隐藏同步点
#pragma omp sections nowait
      {
#pragma omp section
         {
            int s = omp_get_thread_num() + 1;
            sleep(s);
            printf("tid = %d sleep %d seconds\n", s, s);
         }
#pragma omp section
         {
            int s = omp_get_thread_num() + 1;
            sleep(s);
            printf("tid = %d sleep %d seconds\n", s, s);
         }
#pragma omp section
         {
            int s = omp_get_thread_num() + 1;
            sleep(s);
            printf("tid = %d sleep %d seconds\n", s, s);
         }
#pragma omp section
         {
            int s = omp_get_thread_num() + 1;
            sleep(s);
            printf("tid = %d sleep %d seconds\n", s, s);
         }
      }
 
      printf("tid = %d finish sections\n", omp_get_thread_num());
   }
   return 0;
}

运行结果为:

如果不适用nowait,所有的线程会等待直到所有线程完成section内的命令,运行结果就为:

 

对比发现没有nowait的时候所有section运行结束后才会运行section后的代码

代码仓库:

Yoimiya-lover/HPC-learning

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值