• openMP学习笔记 -编程模型


    OpenMP模型

    gcc编译openmp指令:gcc test.cpp -o test -fopenmp

    定积分计算 函数面积

    给定一个定积分,计算其面积:
    ∫ 0 1 4.0 ( 1 + x 2 ) d x \int^{1}_{0}{\frac{4.0}{(1+x^2)}dx} 01(1+x2)4.0dx

    omp 概念

    并行区域

    并行区域用于多线程并行执行指令

    #pragma omp parallel
    {
        ... do lots of stuff
    }//end of parallel region
    
    • 1
    • 2
    • 3
    • 4

    临界区

    临界区用于解决:内存竞争问题,该区块中的代码只能有一个线程执行,其他线程必须等待。

    #pragma omp critical
    {
        ... one or more lines of code
    }
    
    • 1
    • 2
    • 3
    • 4

    栅栏

    栅栏用于解决线程同步问题,通过栅栏设置的锚点,必须等所有线程均执行到该位置才能继续往下执行。

    #pragma omp barrier
    //... continue work
    
    
    • 1
    • 2
    • 3

    栅栏通常用于这种情况,即必须在所有线程完成栅栏前的工作内容,才能继续往下执行。栅栏后的工作内容应当依赖所有线程栅栏前的工作全部完成才能执行,否则得不偿失。
    因为栅栏所带来开销很大。这一点相当于cuda中的同步函数。

    omp相关函数

    • int omp_get_num_threads() : 获取正在运行的线程数
    • int omp_get_thread_num() : 获取线程id
    • void omp_set_num_threads(int) : 获取要执行的线程数
    • double omp_get_wtime() : 返回以秒为单位的时间

    串行执行

    以横坐标为单位划分为指定数量的小块,取每个小块的中值作为该块的值,累加获得最终值。代码如下:

    #include 
    #include 
    #include 
    static long num_steps = 100000000;
    double step;
    int main(){
      int i;
      double x , pi , sum=0.0;
      double start_time , run_time;
      step = 1.0 / (double)num_steps;
      start_time = omp_get_wtime();
      for (int i=0; i
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    以padding的方式解决多线程计算总和问题

    #include 
    #include 
    #include 
    #include 
    #include 
    #define NTHREADS 12
    double func(const double &x){
      return 4.0/(1.0+x*x);
    }
    template double Area(FunctionType func,const double &start, 
                                                const double &end, const long &num_steps){
      double width = (end-start)/num_steps;
      double hight[NTHREADS]={0.0};
      int actual_RunThreads;
      // omp_set_num_threads(NTHREADS);
      double start_time = omp_get_wtime();
      #pragma omp parallel
      {
        //获取线程id
        long thread_ID = omp_get_thread_num();
        //获取实际运行的线程数
        if(!thread_ID) actual_RunThreads = omp_get_num_threads();
        for(long i = thread_ID; i double AreaAgent(FunctionType func ,Args... args){
      return Area( func, args...);
    }
    
    int main(){
      std::function f = func;
      double area =  AreaAgent(f , 0.0 , 1.0 , 100000000);
      std::cout<<"area: "<
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46

    以临界区方式计算面积总和问题

    #include 
    #include 
    #include 
    #include 
    #include 
    double func(const double &x){
      return 4.0/(1.0+x*x);
    }
    template double Area(FunctionType func,const double &start, 
                                                const double &end, const long &num_steps){
      //获取每块的宽度
      //num_steps表示分为多少块
      double width = (end-start)/num_steps;
      double sum=0.0;
      int actual_RunThreads;
      double start_time = omp_get_wtime();
      //并行执行区域
      #pragma omp parallel
      {
        double partial_sum=0.0;
        //获取线程id
        long thread_ID = omp_get_thread_num();
        //获取实际运行的线程数
        if(!thread_ID) actual_RunThreads = omp_get_num_threads();
        //actual_RunThreads表示步长
        for(long i = thread_ID; i double AreaAgent(FunctionType func ,Args... args){
      return Area( func, args...);
    }
    
    int main(){
      std::function f = func;
      double area =  AreaAgent(f , 0.0 , 1.0 , 100000000);
      std::cout<<"area: "<

执行时间统计

线程数串行OMPOMP消除伪共享OMP临界区同步
10.2908212.497372.513762.50391
20.2908212.460012.554351.25341
30.2908212.921661.907810.991777
40.2908214.091341.267990.630626
50.2908213.131442.538150.627318
60.2908212.931121.245410.579776
70.2908212.836552.953340.527468
80.2908212.91950.8268440.458585
90.2908212.394310.8528510.409409
100.2908213.209070.821560.381328
110.2908213.029431.919770.352992
120.2908212.957090.7372330.343221
  • 相关阅读:
    www.7seasnft.com、数字藏品、总结
    相机拍照不清晰怎么回事?不清晰地照片还能修复高清吗?
    android top 参数
    Completeness (order theory)
    android-适配方案-密度适配-最小宽度限定符
    精读服务器默认rsyslog的配置文件
    网络技术八:Vlan和Trunk基础
    记录每天学习的新知识:DataBinding
    在word文档中找不到endnote的选项卡
    Cookie与Session的区别及如何选择
  • 原文地址:https://blog.csdn.net/m0_46327721/article/details/133974514