OpenMP 笔记(C 语言)
贡献者: addis
- 在 Ubuntu 中运行单线程程序,top 命令会显示某个 CPU 的用量是 100. 然而在 Windows 中,貌似这个程序会在所有 CPU 中来回切换,使表面上看起来像是在并行(然而实际上并没有). 当在 windows 中用 OpenMP parallel for 的时候,可以看到所有的 CPU 用量都是 100%.
- 在 Visual Studio 中使用 OpenMP, 只需打开 Project Property > C/C++ > Language > Open MP Support 选 Yes 即可。
- 如果不只是用 pragma 而是用到了 omp 的函数,需要头文件
<omp.h>
- 如何判断 OpenMP 生效了?可以用一个
#pragma omp parallel for
, 如果不是按顺序执行的,就是生效了。
- 要指定 parallel for 的线程数上限,用
omp_set_num_threads()
(用于 override OMP_NUM_THREADS
环境变量)。注意这里是 “上限”,当 runtime 系统决定用更少的线程效果会更好时,就会这么做。如果不希望是 “上限” 而是严格规定,用 omp_set_dynamic(0)
或者设置环境变量 OMP_DYNAMIC
为 false
。
或者局部地
- 还有一种指定线程的方法是用
- 获取当前的总线程数用
omp_get_num_threads()
,这个必须在 parallel 里面执行才不等于 1(例如 parallel for 的内部)
- 获取当前线程编号用
omp_get_thread_num()
-
#pragma omp parallel
让每个线程执行接下来的一个命令(或者 中所有的命令). 如果 中声明了变量,则每个线程中都有一个同名变量。
- [重要] 在 parallel for 之前声明的变量在 parallel for 内也是唯一的,在 parallel for 内声明的变量每个线程都有一个。在 parallel for 之前声明变量是许多常见的 bug 的来源。尤其是 parallel for 内部的 for 循环的循环变量。最好的办法是把 parallel for 内每个被赋值的变量都审核一遍。
- 与 CUDA 不同,parallel for 内部不能有同步,因为一个线程有可能执行不止一个循环。如果要同步就用多个 parallel for, 中间就会自动同步。
- 若要让每个线程执行指定的代码,用 sections
在这个代码中,function1-function4 分别只执行一次,其中被
#pragma omp section
隔开的三个部分允许并行,但 function2() 和 function3() 不允许并行。千万注意两个 section 中不能对同名变量赋值,也就是说同名变量并不会每个线程都复制一份。
现在有一个问题就是如何并行嵌套循环
两个 for 之间没有代码。现在使用的方法是
- atomic 运算与 CUDA 的概念一样,在某个命令前面加上
#pragma omp atomic
即可
-
omp_set_nested(N)
允许 N 重 parallel for 嵌套,默认不允许嵌套(),只对最外层 parallel for 生效。用 gdb
可以追踪线程的数量。例如以下代码的子函数内的 parallel for 就默认会失效,除非把注释去掉。
当并行时一个或多个命令不是 thread safe 的时候,可以把它放在 critical block 里面,这里面一次只有一个 thread 能进入。
一个更高性能的命令是
若想把每个线程中的一个数加到一起,除了 atomic 也有现成的办法(reduction
):
这种把每个线程中的数据累计到一个数中的过程就叫做
reduction,其他并行计算框架也使用这个词。类似的,还有
reduction(max:my_var)
用于计算最大值。
致读者: 小时百科一直以来坚持所有内容免费无广告,这导致我们处于严重的亏损状态。 长此以往很可能会最终导致我们不得不选择大量广告以及内容付费等。 因此,我们请求广大读者
热心打赏 ,使网站得以健康发展。 如果看到这条信息的每位读者能慷慨打赏 20 元,我们一周就能脱离亏损, 并在接下来的一年里向所有读者继续免费提供优质内容。 但遗憾的是只有不到 1% 的读者愿意捐款, 他们的付出帮助了 99% 的读者免费获取知识, 我们在此表示感谢。