专栏首页Yunfeng's Simple BlogOpenMP并行编程简介

OpenMP并行编程简介

在这学期的并行计算课程中,老师讲了OpenMP,MPI,CUDA这3种并行计算编程模型,我打算把相关的知识点记录下来,便于以后用到的时候查阅。

概述

OpenMP是基于共享存储体系的基于线程的并行编程模型。一个共享存储的进程由多个线程组成,而OpenMP就是基于已有线程的共享编程范例。 在OpenMP中,线程的并行化是由编程人员控制的,不是自动编程模型,而是外部变成模型。 OpenMP采用Fork-Join并行执行模型。即程序开始于一个单独的主线程,主线程会一直串行地执行,遇到第一个并行域,通过如下过程完成并行操作:

  1. Fork: 主线程创建一系列并行的线程,由这些线程来完成并行域的代码。
  2. 当所有并行线程完成代码的执行后,它们或被同步或被中断,最后只剩下主线程在执行。

那么并行代码块是如何创建的呢?在OpenMP中,通过编译制导语句(即像#pragma开头的语句)来构造并行域,在原本的串行代码中,在可并行代码块周围添加编译制导语句并修改相应的代码,就可以完成并行的功能。 运行OpenMP代码不需要安装任何额外的库或工具,标准的C/C++代码编译器执行环境就可以执行。 下面是一个简单的OpenMP的例子:

//file name: test_openmp.c
#include <stdio.h>
#include <omp.h>

int main(int argc, char** argv)
{
    int num_thread = 4;

	omp_set_num_threads(num_thread);
	#pragma omp parallel
	{
		int id = omp_get_thread_num();
		printf("hello from thread%d\n",id);
	}

    return 0;
}

通过gcc --openmp test_openmp.c来编译,运行生成的可执行文件,得到结果如下:

hello from thread0
hello from thread3
hello from thread1
hello from thread2

可以看到,各个线程执行的顺序是无序的。

核心知识

下面记录使用OpenMP的一些核心点。

  1. 包含头文件omp.h
  2. 所有并行块由#pragma omp开头的编译制导语句来开始,在代码块周围要有大括号
  3. 常见的编译制导语句有#pragma omp prallel, 表示最基本的循环
  4. #pragma omp parallel for:并行部分包含一个for循环;
  5. #pragma omp critical:并行部分的代码一次只能由一个线程执行,相当于取消了并行化
  6. #pragma omp barrier: 同步并行线程,让线程等待,直到所有的线程都执行到该行
  7. #pragma omp section: 将并行块内部的代码划分给线程组中的各个线程,一般会在内部嵌套几个独立的section语句,可以使用nowait来停止等待
  8. 通过omp_set_num_threads函数来手动设置线程数。可以看到线程数是在程序编写过程中指定的
  9. 通过omp_get_thread_num来获取当前线程的编号
  10. 通过omp_get_num_threads来获取线程总数

一个例子

这里举一个更完善的例子来说明。

#include <iostream>
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <omp.h>
#include <sys/time.h>

int main(int argc, char** argv)
{
	struct timeval start, end;
	gettimeofday(&start, NULL);

    if (argc != 3)
    {
        std::cout << "USAGE: num_primer <num_of_thread> <integer>" << std::endl;
        return -1;
    }

    int num_thread = atoi(argv[1]);
    int n = atoi(argv[2]);

	std::cout << "num of thread: " << num_thread << std::endl;
	std::cout << " n: " << n << std::endl;
    int* num_primer = new int[num_thread];
	for (int i = 0; i < num_thread; ++i)
	{
		num_primer[i] = 0;
	}

	omp_set_num_threads(num_thread);
	#pragma omp parallel shared(n, num_primer)
	{
		int id = omp_get_thread_num();
		
    	for (int i = id + 2; i < n + 1; i = i + num_thread)
    	{
			bool has_factor = false;
			#pragma omp parallel shared(n, i, num_primer, has_factor)
			{
				for (int j = 2; j < int(sqrt(i)) + 1; ++j)
				{
					if (i % j == 0)
					{
						has_factor = true;
						break;
					}
				}
				if (!has_factor)
				{
					++num_primer[id];
					std::cout << "id: "<< id << ", primer:" << i << std::endl;
				}
			}//pragma
    	}
	}//pragma
	
	//add all primers
	int sum_num_primer = 0;
	for (int i = 0; i < num_thread; ++i)
	{
		sum_num_primer += num_primer[i];	
	}

	std::cout << "The number of primers between 0 and " << n << " is: " << sum_num_primer << std::endl;

	gettimeofday(&end, NULL);
	double time_gap = (end.tv_sec - start.tv_sec) * 1000000u + end.tv_usec - start.tv_usec;
	printf("Time cost: %.2lf s.\n", time_gap / 100000);

    return 0;
}

参考文献

并行计算——结构,算法,编程(第3版),陈国良

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • ScalaMP ---- 模仿 OpenMp 的一个简单并行计算框架

    Ldpe2G
  • Caffe:CPU模式下使用openblas-openmp(多线程版本)

    版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net...

    用户1148648
  • ScalaMP ---- 模仿 OpenMp 的一个简单并行计算框架

    这个项目是一次课程作业,要求是写一个并行计算框架,本人本身对openmp比较熟,

    Ldpe2G
  • 大数据并行计算利器之MPI/OpenMP

    1 背景 图像连通域标记算法是从一幅栅格图像(通常为二值图像)中,将互相邻接(4邻接或8邻接)的具有非背景值的像素集合提取出来,为不同的连通域填入数字标记,并且...

    CSDN技术头条
  • xgboost 多线程,解决默认开启线程数为cpu个数问题

    在一台48c的服务器上,就import xgboost,还没进行训练,通过命令发现,线程数就达到48个 代码:

    lovelife110
  • 利用OpenMP实现埃拉托斯特尼(Eratosthenes)素数筛法并行化

    筛法是一种简单检定素数的算法。据说是古希腊的埃拉托斯特尼(Eratosthenes,约公元前274~194年)发明的,又称埃拉托斯特尼筛法(sieve of E...

    Dabelv
  • C++多线程-多核编程

    多核编程并不是最近才兴起的新鲜事物。早在intel发布双核cpu之前,多核编程已经在业内存在了,只不过那时候是多处理器编程而已。为了实现多核编程,人们开发实现了...

    cwl_java
  • 波动方程求解器的任务低效模式

    复杂算法的编排需要高水平的自动化,以高效地使用现代硬件。使用OpenMP进行基于任务的编程是实现这一目标的最佳选择。我们研究了OpenMP5在波动方程求解器(E...

    猪猪奶茶三分糖
  • 并发编程之各种锁的简介

    一、公平锁/非公平锁 公平锁是指多个线程按照申请锁的顺序来获取锁。 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优...

    lyb-geek
  • xmake v2.3.8 发布, 新增 Intel C++/Fortran 编译器支持

    xmake 是一个基于 Lua 的轻量级跨平台构建工具,使用 xmake.lua 维护项目构建,相比 makefile/CMakeLists.txt,配置语法更...

    ruki
  • 如何成为一名异构并行计算工程师

    用户1737318
  • 并行计算——OpenMP加速矩阵相乘

            OpenMP是一套基于共享内存方式的多线程并发编程库。第一次接触它大概在半年前,也就是研究cuda编程的那段时间。OpenMP产生的线程运行于C...

    方亮
  • [视频编码] 怎么在Visual Studio上启用OpenMP

    OpenMP 是一种支持共享存储并行设计的库,特别适宜在多核CPU上的并行程序设计

    轻舞飞扬SR
  • 开源项目介绍 | ncnn-神经网络推理框架

    2021腾讯犀牛鸟开源人才培养计划 开源项目介绍 滑至文末报名&提交项目Proposal ? ? ncnn项目介绍 ? ncnn是一个为手机端极致优化的高性能...

    腾讯开源
  • Caffe:CPU模式下使用Intel MKL做mnist训练

    版权声明:本文为博主原创文章,转载请注明源地址。 https://blog.csdn.net...

    用户1148648
  • win32编程简介

      我们要编写windos程序.都离不开API. 也就是我们所说的win32程序. 所以学好win32是你能不能再windows下编写程序的基础.

    IBinary
  • C++编程简介

    面向对象是种观念,我们用这种观念来写程序。需要面向对象的语言,而 c++就是支持面向对象观念的一种语言。

    清菡
  • 聊聊并行并行编程

    所谓性能,更像是可扩展性以及效率。不再聚焦于单个CPU的性能,而是在于平均下来CPU的性能。这个来源于摩尔定律的失效,

    哒呵呵
  • OpenPower来了,我的代码怎么办?

    OpenPOWER:X86的另一种选择 2013年8月6日,谷歌、IBM、Tyan、NVIDIA和Mellanox一起创立了后来被称之为OpenP...

    GPUS Lady

扫码关注云+社区

领取腾讯云代金券