精华内容
下载资源
问答
  • OpenMP并行编程

    2019-10-09 04:47:47
    OpenMP并行编程 什么是OpenMP?“OpenMP (Open Multi-Processing) is an application programming interface (API) that supports multi-platform sha...
    • 什么是OpenMP?
      “OpenMP (Open Multi-Processing) is an application programming interface (API) that supports multi-platform shared memory multiprocessing programming in C, C++ and Fortran on many architectures, including Unix and Microsoft Windows platforms. It consists of a set of compiler directives, library routines, and environment variables that influence run-time behavior. ”
      简单来说,OpenMP是一个可以应用于多种平台的共享内存式并行计算的接口。
    • Openmp的工作模式:
      Openmp的工作模式为串行-并行-串行…。一开始的主线程是串行,当在需要并行的时候(这时候程序中应该有相应的Openmp指令语句),多个线程开始一起工作。若当前的并行块结束(仍旧由相应的Opemp指令语句来控制)时,又重新回到单一的主线程。如此可往复继续。在一个四核心cpu上运行Openmp程序(并行块的线程数默认是核心数目,这里即为4个线程),程序处于主线程时cpu利用率为100%,但是当程序进入并行块时所有的核心都会参与进来,cpu利用率会达到400%。如果程序的主要运算部分都处于并行区域,则绝大部分时间cpu都处于400%的工作状态,这样便大大提高cpu的利用率。
    • Openmp程序的结构:
      正如上面所说,编写Openmp程序只需要在已有的串行程序上稍加修改即可:在并行开始和结束的地方加上Openmp语句引导并行的开始和结束。这些引导语句本身处于注释语句的地位,必须在编译时加上Openmp并行参数才能使其生效。如果不加编译参数,编译出来的程序仍旧是串行程序。
      Openmp是最容易实现的并行方式。
    • Openmp程序的编写:
      下面以fortran语言为例说明Openmp程序的编写(对c语言和fortran语言,都可以参考本文最后给出的openmp教程)。一般的格式为

       

      !$omp parallel CLAUSE
      !$omp DIRECTION
      [ structured block of code ]
      !$omp end DIRECTION
      !$omp end parallel

      其中DIRECTION是Openmp指令,有sections,do等,指定并行行为。中间的

      [ structured block of code ]

      即是需要并线的程序块。除了上面的称为DIRECTION的指令语句外,Openmp还需要称为CLAUSE的从句对并行进行限制和说明。比如,需要对私有变量进行声明时就需要用到private从句(这是经常要遇到的,后面会以例子说明)。在fortran的串行编译下,以“!”打头的都处于屏蔽状态是不起作用的。加了openmp编译参数后才会生效。

      我在程序编写中用到最多的是do指令,偶尔用一下sections。do指令通常用来并行化do循环。本来用一个线程来执行的长的do循环被分割成几个部分让多个线程同时执行,这样就节省了时间。sections指令通常用来将前后没有依赖关系的程序块(也即原本不分先后,你换下顺序也无所谓)并行化。因为无关联,所以可以同时执行。

      可以说,若程序主要用来做计算,掌握了do和sections这两个指令足矣!

    • 简单的程序例子:
      1.Sections 指令的应用:

       

      !$OMP PARALLEL SHARED(A,B,C), PRIVATE(I)   !//Paralell块开始
      !$OMP SECTIONS  !//Sections开始
      !$OMP SECTION     !//第一个section
      DO I = 1, N/2
      C(I) = A(I) + B(I)
      END DO
      !$OMP SECTION    !//第二个section
      DO I = 1+N/2, N
      C(I) = A(I) + B(I)
      END DO
      !$OMP END SECTIONS NOWAIT       !//Sections结束
      !$OMP END PARALLEL     !//Paralell块结束

      这个并行语句将本来从1到N的循环手动分为两个部分并行执行。上面的shared,private就是从句(clause),声明A,B,C为公有的,而循环指标I是私有的。因为两个section同时执行,都会对I进行改变,所以两个section的循环指标必须彼此独立,不能是同一个变量。PRIVATE会自动将这个会引发冲突的变量按需生成多个拷贝以供使用。最后的!$OMP END SECTIONS NOWAIT语句告诉两个线程可各自自行结束,无需相互等待。

      2.Do 指令的应用:
      上面用Section实现的功能完全可以用Do来实现:

      !$OMP PARALLEL SHARED(A,B,C), PRIVATE(I)    !//Paralell块开始
      !$OMP DO    !//Do的并行开始
      DO I = 1, N
      C(I) = A(I) + B(I)
      END DO
      !$OMP END DO   !//Do的并行结束
      !$OMP END PARALLEL   !//Paralell块结束

      Do循环本来是从1到N,现在有多少个线程就分为多少个部分执行,比上面的section更方便智能。不用担心循环次数N不能被线程数整除~。一般情况下,各个线程均分循环次数,但是在某些循环指标下运算可能比较快,所以各个线程的运算时间可能不尽相同。这时候如果需要让各个线程都结束了才能再往下(没有NOWAIT),快的线程就必须等待慢的线程。为了解决这个问题需要加上schedule从句,首行变为如下:

      !$OMP PARALLEL SHARED(A,B,C), PRIVATE(I),SCHEDULE(DYNAMIC)

      这个SCHEDULE(DYNAMIC)从句告诉程序动态调整并线方式,那些任务轻松运算快的线程会自动去帮任务重运算慢的线程,力争所有线程同时完成任务。

      关于Do的积累计算,如累加,需要加上REDUCTION从句:

      C=0.d0
      !$OMP PARALLEL SHARED(A,C), PRIVATE(I),REDUCTION(+:C)
      !$OMP DO
      DO I = 1, N
      C =C+ A(I)
      END DO
      !$OMP END DO
      !$OMP END PARALLEL

      这里将累加分为几个部分由多个线程进行运算,由于各个线程都在0.d0的基础上开始计算它该算的部分,所以最后必须将各部分计算的结果再次求和。REDUCTION(+:C)从句就实现了这个效果。类似的叠乘等等用类似写法,只需把“:”前的运算符改为乘法“*”即可。

    • 一些注意问题:
      1.尤其要注意的问题就是变量的私有和公有问题。其实只要把握好一个原则,即如果这个变量有可能会被不同的线程同时进行写操作(这不是你希望看到的),则这个变量就应该声明为私有。一般来说,并行体中临时用到的一些中间变量应该是私有的。

       

      2.据我的经验,Fortran中如果不特别声明,变量都是默认公有的。这一点可以用DEFAULT(PRIVATE/SHARED)从句强行改变。循环指标默认是私有的,无需自己另外声明。放在common域中的变量都是全局的,若要将这些全局变量私有化,可使用threadprivate指令(参见文章:OpenMP并行编程:threadprivate指令)。

      3.并行引导语句可以简化,但要注意前后配对。比如上面那个累加的例子可以这样写:

      C=0.d0
      !$OMP PARALLEL DO SHARED(A,C), PRIVATE(I),REDUCTION(+:C)
      DO I = 1, N
      C =C+ A(I)
      END DO
      !$OMP END PARALLEL DO

      也即可以将从句加在指令之后。

      4.Fortran+Openmp的编译问题:
      一般来说,加上-openmp编译参数即可。如:
      ifort -openmp -o exe.out main.f
      gfortran用-fopenmp编译参数,g77和ifort一样用-openmp参数。
      如果用Makefile,将编译参数放在合适的地方。

      5.对于多重do循环,如果中间变量太多,对私有公有弄不清楚或者虽然清楚但是闲麻烦,可以保留最外层循环,将里面的循环在别处写成一个子函数或子程序 ,然后在此处调用。这样从结构上看就是对一重循环进行并行化,条理清楚不容易出错。当然,传递给子函数或子程序的参数一般是要声明私有的。

      6.将串行程序改为Openmp并行程序后,在加与不加-openmp编译参数的情况下分别编译并运算,比较并行与串行的结果,确保并行块没有改错。

      7.可以在并行开始前指定由多少个线程来并行。在单cpu单核心的机器上也可以(虽然没有实际意义,但可以用来调试并行程序):

      CALL OMP_SET_NUM_THREADS(scalar_integer_expression)

      其中scalar_integer_expression是个整形变量,指定并行的线程数目。

      8.Openmp对私有变量的大小有限制。所以当遇到这样的情况,一般就是由这个限制造成的:不加openmp并行时程序没有问题,加了openmp并行时出现断错误(segmentation fault),但是当把某个(一些)私有数组的维数变小时,段错误消失而且和串行时结果一致。
      解决办法(linux下,windows下另外search)如下:
      在linux终端执行
      ulimit -s unlimited ;export KMP_STACKSIZE=2048000
      后一个数字参数足够大即可。

    posted on 2014-01-01 10:24 向北方 阅读(...) 评论(...) 编辑 收藏

    转载于:https://www.cnblogs.com/China3S/p/3500412.html

    展开全文
  • openMP 并行编程

    2019-01-08 20:09:30
    OpenMP 入门教程: https://www.cnblogs.com/ospider/p/5265975.html openMP的一点使用经验: ... OpenMP共享内存并行编程详解: https://www.cnblogs.com/liangliangh/p/3565234.ht...
    展开全文
  • 多核环境下OpenMP并行编程 文章目录多核环境下OpenMP并行编程一、实验环境二、实验内容三、实验目的四、实验步骤4.1 Windos下编译并运行OpenMP程序4.1.1 环境配置4.1.2 代码4.1.3 运行结果4.2 Linux平台上编译和运行...

    多核环境下OpenMP并行编程

    一、实验环境

    操作系统:Windows 10、Linux(Centos 7 虚拟机)

    运行环境:Visual Stdudio 2019(cl)、Vim(g++)、VMware Workstation Pro

    CPU处理器:AMD Zen2 3700x @3.8Ghz 8c16t ,4c4t(虚拟机)

    二、实验内容

    学习编制多线程并行程序实现如下功能:

    1.创建多线程,输出线程号和线程数。

    2.学习for多线程并行。

    3.学习while多线程并行,实现全局共享变量存取。

    4.编程实现大规模向量的并行计算

    三、实验目的

    1.掌握OpenMP并行编程基础;

    2.掌握在Linux平台上编译和运行OpenMP程序;

    3.掌握在Windows平台上编译和运行OpenMP程序。

    4.用OpenMP实现最基本的矩阵乘法以及性能分析

    四、实验步骤

    4.1 Windos下编译并运行OpenMP程序

    4.1.1 环境配置

    在vs的(项目)(属性)(配置属性)(C/C++)(语言)中设置(OpenMP支持)为(是),并将其中的符合模式设置为(否)

    在这里插入图片描述

    4.1.2 代码

    #include <omp.h>
    #include <stdio.h>
    int main() {
    	int nthreads, tid;
    	omp_set_num_threads(8);
    	#pragma omp parallel private(nthreads, tid)
    	{
    		tid = omp_get_thread_num();
    		printf("Hello World from OMP thread %d\n", tid);
    		if (tid == 0) {
    			nthreads = omp_get_num_threads();
    			printf("Number of threads is %d\n", nthreads);
    		}
    	}
    }
    

    4.1.3 运行结果

    在这里插入图片描述

    4.2 Linux平台上编译和运行OpenMP程序

    4.2.1 环境配置:

    安装g++:yum install g++

    编译参数:g++ -fopenmp -o

    测试代码同4.1.2windows环境下的代码

    4.2.3 运行结果

    在这里插入图片描述

    4.3 多线程实现矩阵乘法

    4.3.1 TimeCalculate() 计时函数

    void TimeCalculate() {
        static bool is_record = 1;
        is_record = 1 - is_record;
        static clock_t TimeStart = clock();
        if (is_record == 0)
            TimeStart = clock();
        else {
            const clock_t TimeEnd = clock();
            std::cout << "This costs: ";
            std::cout << (double)(TimeEnd - TimeStart) / CLK_TCK * 1000;
            std::cout << " ms." << std::endl;
        }
    }
    

    通过static全局静态变量,可以实现运行该函数开始计时,再次运行停止计时,并输出时间花费。

    4.3.2 Matrix 矩阵类和矩阵乘法

    class Matrix {
    public:
        int rows; // 行
        int cols; // 列
        float* elements;
    
        Matrix(int rows, int cols, float v) :rows(rows), cols(cols) {
            elements = new float[rows * cols];
            for (int i = 0; i < cols * rows; i++) elements[i] = v;
        }
    
        Matrix(int rows, int cols, float *v) :rows(rows), cols(cols) {
            elements = new float[rows * cols];
            for (int i = 0; i < cols * rows; i++) elements[i] = v[i];
        }
        
        ~Matrix() {
            delete[] elements;
        }
    };
    
    void MatMul(Matrix& A, Matrix& B, Matrix& ret) {
        for (int i = 0; i < A.rows; i++) {
            for (int j = 0; j < B.cols; j++) {
                float t = 0;
                for (int k = 0; k < A.cols; k++)
                    t += A.elements[i * A.cols, k] * B.elements[k * B.cols + j];
                ret.elements[i * ret.cols + j] = t;
            }
        }
    }
    

    Matrix矩阵类提供了两种构造方式,分别为(行,列,元素值)和(行,列,元素值数组)

    MatMul()函数传入三个矩阵引用,分别是矩阵A、矩阵B和结果矩阵ret,通过三层循环得到结果矩阵ret

    4.3.3 并行实现多次矩阵乘法

    void test1(int t_num) {
        Matrix A(4, 4, 1), B(4, 4, 2), C(4, 4, 0.0);
        int per = 10000000 / t_num;
        omp_set_num_threads(t_num);
        int t, i;
        #pragma omp parallel for
        for (t = 0; t < t_num; t++) {
            for (i = 0; i < per; i++) {
                MatMul(A, B, C);
            }
        }
    }
    

    传入参数为使用的线程数t_num,该函数计算了1000万次4*4的矩阵乘法,使用了t_num个线程进行并行,每个线程计算10000000 / t_num次矩阵乘法,当t_num等于1时,原函数相当于串行计算。

    4.3.4 并行实现单次大矩阵乘法

    重写MatMul()函数

    void MatMul2(Matrix& A, Matrix& B, Matrix& ret, int t_num) {
        omp_set_num_threads(t_num);
        #pragma omp parallel default(shared)
        {
            int id = omp_get_thread_num();
            for (int i = 0; i < A.rows; i++) {
                if (i % t_num != id) continue;
                for (int j = 0; j < B.cols; j++) {
                    float t = 0;
                    for (int k = 0; k < A.cols; k++)
                        t += A.elements[i * A.cols, k] * B.elements[k * B.cols + j];
                    ret.elements[i * ret.cols + j] = t;
                }
            }
        }
    }
    

    MatMul2()函数传入三个矩阵引用和线程数t_num,矩阵分别是矩阵A、矩阵B和结果矩阵ret,先调用omp_set_num_threads()初始化并行线程个数,通过最外层的同余判断,使得线程id计算第i%t_num==id轮循环,从而达到并行计算的效果。

    void test2(int t_num) {
        Matrix A(2000, 2000, 3), B(2000, 2000, 2), C(2000, 2000, 0.0);
        MatMul2(A, B, C, t_num, A.cols * A.elements[0] * B.elements[0]);
    }
    

    传入参数为使用的线程数t_num,该函数计算通过调用MatMul2()函数,使用t_num个线程并行计算两个2000*2000的矩阵。

    五、性能分析

    5.1 加速比

    ​ 加速比(speedup)是同一个任务在单处理器系统和并行处理器系统中运行消耗的时间的比率,用来衡量并行系统或程序并行化的性能和效果。

    加速比SpS_p以如下公式定义:Sp=T1TpS_p=\frac{T_1}{T_p}

    其中pp 指CPU数量,T1T_1指顺序执行的执行时间,TpT_p指当有pp个处理器时,并行算法执行的时间

    5.2 并行实现多次矩阵乘法性能

    在这里插入图片描述
    在这里插入图片描述

    5.3 并行实现单次大矩阵乘法性能

    在这里插入图片描述
    在这里插入图片描述

    5.4 性能分析

    ​ 通过上面四张图我们可以看出随着线程数的增加,运行时间先减小后增大,并在16线程时取到最小值;加速比先增大后减小,同样在16线程时取到最大值。线程数量在1至16时,线程数量没增加一倍,运行耗时和加速比变为原来的二分之一多,加速比变为原来的两倍不到,而在超过16线程时,运行时间不再继续下降,反而还会略有上升,加速比同理。

    ​ 可能的原因分析:上述实验是在AMD Zen2 3700x @3.8Ghz 8c16t的硬件环境下完成的,这颗CPU共有8个物理核心,16个线程(下图为任务管理器截图)

    在这里插入图片描述

    ​ 因此在使用和处理器相同的16线程进行测试时,会取得最大的运行效率,而在线程数量超过16时,前16线程组线程并行,但其余线程需要等待还未结束的线程让出资源才能开始启动,相较于前16线程是串行执行的,而线程的切换还需要耗费额外时间,因此反而可能不及仅有16线程的效率。

    六、实现感想

    ​ 在本次实验我学了解了OpenMP语句的基本语法和用法。相较于CUDA并行编程,OpenMP实现起来比较简单,仅需要通过预编译指令以及一些简单的库函数就可以完成复杂的并行计算,在如今处理器向多核发展的大环境下,并且带来十分不错的计算效率和加速比。此外要注意在OpenMP的编程过程中,使用的线程数量不宜超过实体CPU的线程数量,否则会带来效率上的下降。最后也不是所有程序都需要用到并行计算,部分小规模运算使用并行反而会增大开销,而另一部分则只能通过串行来解决。

    七:附录(完整测试代码)

    #include <omp.h> // OpenMP编程需要包含的头文件
    #include <bits/stdc++.h>
    
    using namespace std;
    
    void TimeCalculate() {
        static bool is_record = 1;
        is_record = 1 - is_record;
        static clock_t TimeStart = clock();
        if (is_record == 0)
            TimeStart = clock();
        else {
            const clock_t TimeEnd = clock();
            std::cout << "This costs: ";
            std::cout << (double)(TimeEnd - TimeStart) / CLK_TCK * 1000;
            std::cout << " ms." << std::endl;
        }
    }
    
    class Matrix {
    public:
        int rows; // 行
        int cols; // 列
        double* elements;
    
        Matrix(int rows, int cols, double v) :rows(rows), cols(cols) {
            elements = new double[rows * cols];
            for (int i = 0; i < cols * rows; i++) elements[i] = v;
        }
    
        Matrix(int rows, int cols, double *v) :rows(rows), cols(cols) {
            elements = new double[rows * cols];
            for (int i = 0; i < cols * rows; i++) elements[i] = v[i];
        }
    
        ~Matrix() {
            delete[] elements;
        }
    };
    
    void MatMul1(Matrix& A, Matrix& B, Matrix& ret) {
        for (int i = 0; i < A.rows; i++) {
            for (int j = 0; j < B.cols; j++) {
                double t = 0;
                for (int k = 0; k < A.cols; k++)
                    t += A.elements[i * A.cols, k] * B.elements[k * B.cols + j];
                ret.elements[i * ret.cols + j] = t;
            }
        }
    }
    void MatMul2(Matrix& A, Matrix& B, Matrix& ret, int t_num, double v) {
        omp_set_num_threads(t_num);
        #pragma omp parallel default(shared)
        {
            int id = omp_get_thread_num();
            for (int i = 0; i < A.rows; i++) {
                if (i % t_num != id) continue;
                for (int j = 0; j < B.cols; j++) {
                    double t = 0;
                    for (int k = 0; k < A.cols; k++)
                        t += A.elements[i * A.cols, k] * B.elements[k * B.cols + j];
                    ret.elements[i * ret.cols + j] = t;
                }
            }
        }
        int f = 1;
        for (int i = 0; i < ret.cols * ret.rows; i++) {
            if (abs(ret.elements[i] - v) > 1e-2) {
                cout << i / ret.cols  << " " << i % ret.cols << " " <<  v << " " << ret.elements[i] << endl;
            }
        }
        if (!f) cout << "error!\n";
    }
    
    double getrd() {
        return 10.0 * rand() / RAND_MAX;
    }
    void test1(int t_num) {
        Matrix A(4, 4, getrd()), B(4, 4, getrd()), C(4, 4, 0.0);
        int per = 10000000 / t_num;
        omp_set_num_threads(t_num);
        int t, i;
        #pragma omp parallel for
        for (t = 0; t < t_num; t++) {
            for (i = 0; i < per; i++) {
                MatMul1(A, B, C);
            }
        }
    }
    void test2(int t_num) {
        Matrix A(2000, 2000, getrd()), B(2000, 2000, getrd()), C(2000, 2000, 0.0);
        MatMul2(A, B, C, t_num, A.cols * A.elements[0] * B.elements[0]);
    }
    int main() {
        for (int i = 1; i <= 128; i *= 2) {
            TimeCalculate();
            cout << "Thread num: " << i << endl;
            test1(i);
            TimeCalculate();
        }
    
        for (int i = 1; i <= 128; i *= 2) {
            TimeCalculate();
            cout << "Thread num: " << i << endl;
            test2(i);
            TimeCalculate();
        }
    }
    
    展开全文
  • 原创: jidor 泛智能时代 OpenMP 设计哲学和优点环境要求Windows / Visual Studio 平台Linux / GCC 平台示例源代码...id原子操作与同步高阶实例演示后 记OpenMP 设计哲学和优点OpenMP 是一套 C++ 并行编程框架, 也支...
    331232b2f6d276ddefd56532e7218a78.png

    原创: jidor 泛智能时代

    OpenMP 设计哲学和优点

    环境要求

    Windows / Visual Studio 平台

    Linux / GCC 平台

    示例源代码

    验证支持 OpenMP

    可并行前提

    实例练习

    入门示例:并行输出

    并行输出, 非 OpenMP 实现

    OpenMP 求累加和

    获取线程索引 id

    原子操作与同步

    高阶实例演示

    后 记

    OpenMP 设计哲学和优点

    OpenMP 是一套 C++ 并行编程框架, 也支持 Forthan .

    它是一个跨平台的多线程实现, 能够使串行代码经过最小的改动自动转化成并行的。具有广泛的适应性。这个最小的改动,有时候只是一行编译原语!(在高阶示例中,我们将演示并评估加速性能)

    具体实现是通过分析编译原语#pragma,将用原语定义的代码块,自动转化成并行的线程去执行。每个线程都将分配一个独立的id. 最后再合并线程结果。

    问题来了,学习 OpenMP , 我们怎么开始?

    环境要求

    在开始之前,我们先确定一下我们的 C++ 编译环境能不能支持 OpenMP.

    Windows / Visual Studio 平台

    VS 版本不低于2015,都支持 OpenMP .

    需要在 IDE 进行设置,才能打开 OpenMP 支持。

    设置方式:

    调试->C/C++->语言->OpenMP支持

    这实际上使用了编译选项/openmp。

    Linux / GCC 平台

    本人用的 Ubuntu 16.04 (经典版) 自带的GCC 5.0.4, 直接支持选项-fopenmp.

    示例源代码

    本节所有的代码均放在个人 Github:

    tlqtangok > openmp_demo

    git clone https://github.com/tlqtangok/openmp_demo.git

    验证支持 OpenMP

    如果已经设置好了,我们就开始编程来 Double Check 一下吧。

    参考目录 00_dep

    #include using namespace std;int main(){#if _OPENMP cout << " support openmp " << endl;#else cout << " not support openmp" << endl;#endif return 0;}

    运行代码:

    g++ -std=c++11 -g -pthread -Wno-format -fpermissive -fopenmp -o main.o -c main.cppg++ -std=c++11 -g -pthread -Wno-format -fpermissive -fopenmp -o mainapp.exe main.o./mainapp.exe

    运行输出

     support openmp

    即表明我们支持 OpenMP 了。

    接下来我们就可以进入正题了。

    可并行前提

    要想并行,就需要满足如下的条件:

    • 可拆分
    • 代码和变量的前后不能相互依赖。
    • 独立运行
    • 运行时,拥有一定的独有的资源。像独有的线程id等。

    其它理论的知识,请自行阅读计算机体系结构之类的计算机基础。 本 chat 着重讲讲实际操作技能。

    实例练习

    入门示例:并行输出

    目录 01_parallel_cout

    • 正常顺序输出 0 ~ 10
    for(int i=0; i< 10; i++){ cout << i << endl; }

    这样子,0~10 是顺序打印的。

    我们要并行的运行打印,即乱序的输出 0~10 才能证明并行运行(而且运行结果不一定一致)。

    • 用 OpenMP 容易实现并行输出
    #include #include  // NEW ADDusing namespace std;int main(){ #pragma omp parallel for num_threads(4) // NEW ADD for(int i=0; i<10; i++) { cout << i << endl; } return 0;}

    运行之后, 结果是:

    jd@ubuntu:/mnt/hgfs/et/git/openmp_demo/01_parallel_cout$ make rung++ -std=c++11 -g -pthread -Wno-format -fpermissive -fopenmp -o main.o -c main.cppg++ -std=c++11 -g -pthread -Wno-format -fpermissive -fopenmp -o mainapp.exe main.o./mainapp.exe3458967012

    可以看到乱序了!说明我们的 OpenMP 并行起了作用。

    这里只多加了两行代码,就并行化了这个任务。是不是很简洁。

    解析上面新加的两行:

    #include

    OpenMP 的编译头文件,包括一些常用API,像获取当前的线程id.

    #pragma omp parallel for num_threads(4)

    用编译原语,指定其下面的代码块将会被渲染成多线程的代码,然后再编译。这里使用的线程数为 4。对比一下不用 OpenMP 的代码,你一定会感叹, OpenMP 真香。

    并行输出, 非 OpenMP 实现

    为了模拟自己实现 OpenMP 的 for 框架, 我做了以下尝试…

    总之, 代码量不少,约 135 行,还很容易出错。作为对比,大家运行一下,看看就好。

    具体请看目录 02_parallel_no_omp.

    OpenMP 求累加和

    代码请看 03_reduce

    求1~100 之和, 用 32 个线程并行

     int sum = 0; #pragma omp parallel for num_threads(32) for(int i=0; i<100; i++) { sum += i;  } cout << sum << endl;

    标准答案是 4950, 但是,运行的结果有时候是 4950, 有时候却不是。

    为什么呢?

    因为其中产生了竞争。

    sum += i; 这一行如果多个线程同时写,可能会发生写冲突。

    关于这些 reduce 的问题,OpenMP 也有专门的原语来帮我们,让我们小小地改动一下就行了。

     int sum = 0; #pragma omp parallel for num_threads(32) reduction(+:sum) for(int i=0; i<100; i++) { sum += i;  } cout << sum << endl; 

    我们只要亮出sum 是要保护的 reduce 变量就可以了 !

    获取线程索引 id

    每个线程都有自己的身份,表明他是第几号。

    获取这个第几号可以方便调试。

    在 OpenMP 中,这个id很容易获取。本人一般喜欢用idx来表示这个id.

    请看 04_get_idx

    #define DEFINE_idx auto idx = omp_get_thread_num();#define _ROWS (omp_get_num_threads())

    在块内定义idx, 就可以用了:

     #pragma omp parallel for num_threads(3)  for(int i=0; i<10; i++) { DEFINE_idx; printf("- idx is %d, i is %d, total thread num is %d
    展开全文
  • openMP 并行编程基础

    2012-03-21 10:25:33
    openMP 并行编程基础 1、fork/join并行执行模式的概念 OpenMP是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的。 前面一篇文章中已经试用了OpenMP的一个Parallel for...
  • C++之OpenMP并行编程——枚举排序环境设置算法设计源代码运行结果: 环境设置 (这是自己高新能与云计算课程的一个作业)可以看之前那篇Visual Studio 2017之OpenMP运行环境配置 算法设计 枚举排序算法: 是一种最...
  • 1.OpenMP OpenMP是一种用于共享内存并行系统的多线程程序设计的库(Compiler Directive),特别适合于多核CPU上的并行程序开发设计。它支持的语言包括:C语言、C++、Fortran;不过,用以上这些语言进行程序开发时,并非...
  • 第六章-重点:OpenMP并行编程 OpenMP 定义 共享存储体系结构上的一个并行编程模型或基于线程的并行编程模型 代码(一定会考一个) /* 用OpenMP/C编写Hello World代码段 */ #include <stdio.h> #include &...
  • 在程序编写的复杂程度上,OpenMP只需在串行程序上做少许的改动即可实现并行,而MPI的编程往往比较复杂,一般与串行程序是两套不同的代码。本文简单介绍Fortran语言下使用OpenMP实现并行的方法。话不多说,直接上一个...
  • openMP 并行编程 基础

    2009-02-09 10:22:59
    openMP 并行编程 基础 1、fork/join并行执行模式的概念 OpenMP是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的。 前面一篇文章中已经试用了OpenMP的一个P...
  • openMP并行编程基础

    2020-11-26 21:40:26
    OpenMP基础结构: 例程: #include <iostream> #include <omp.h> #include <cstdio> #include <bits/stdc++.h> using namespace std; int main(int argc, char *argv[]){ int nt, tid; ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 638
精华内容 255
关键字:

openmp并行编程