自学内容网 自学内容网

OpenMP并行编程实例系列3 —— 线程设置

OpenMP 线程设置

OpenMP 可以在程序中设置线程数,常用的有 3 种方式:

  • 使用环境变量 OMP_NUM_THREADS 设置线程数;
  • 调用 OpenMP 的环境函数 omp_set_num_threads 设置线程数;
  • 直接在 #pragma omp 语句中使用 num_threads 关键字设置线程数。

另外,还支持在多个嵌套级别上控制线程数(不同嵌套中线程可以不同)。以下的实例展示如何使用环境变量 OMP_NUM_THREADS 在多个嵌套级别上控制线程数量,为了理顺逻辑,我添加了一些打印信息。

// desc: Controlling the Number of Threads on Multiple Nesting Levels
// file: omp_nthrs_nesting.cpp

#include <cstdio>
#include <omp.h>

int main(int argc, char const *argv[])
{
    omp_set_nested(1);// 设置允许嵌套并行
    omp_set_dynamic(0);// 静止动态改变线程数
    #pragma omp parallel
    {
        int tid1 = omp_get_thread_num();
        printf("-1: %d\n", tid1);
        #pragma omp parallel
        {// 嵌套并行
            int tid2 = omp_get_thread_num();
            printf("-2: %d - %d\n", tid1, tid2);
            #pragma omp single
            {
                printf("inner1: num threads %d\n", omp_get_num_threads());
            }
        }

        #pragma omp barrier
        omp_set_nested(0);
        #pragma omp parallel
        {
            int tid2 = omp_get_thread_num();
            printf("-3: %d - %d\n", tid1, tid2);
            #pragma omp single
            {
                printf("inner2: num threads %d\n", omp_get_num_threads());
            }
        }

        #pragma omp barrier
        printf("-4: %d\n", tid1);
        #pragma omp single
        {
            printf("outter: num threads %d\n", omp_get_num_threads());
        }
    }

    return 0;
}

程序中一些 omp 子句的说明:

  • #pragma omp single

    指定并行域中的串行任务,创建仅由一个线程执行的任务,先到先执行,其他线程等待其执行结束后再一起执行后面的任务。

  • #pragma omp barrier

    等待同步:用在并行域内,所有线程执行到 barrier 都要停下等待,直到所有线程都执行到 barrier,然后再继续往下执行

以下是线程数为 2 和 3 的输出结果

$ export OMP_NUM_THREADS=2# 通过环境变量,设置线程数为2
$ ./omp_nthrs_nesting
-1: 0# 外层的线程
-1: 1
-2: 0 - 0# 嵌套的线程
inner1: num threads 2# single输出
-2: 0 - 1
-2: 1 - 0
inner1: num threads 2# single输出
-2: 1 - 1
-3: 0 - 0 # 外层线程,禁止嵌套
inner2: num threads 1# single输出
-3: 1 - 0
inner2: num threads 1# single输出
-4: 0# 外层线程
outter: num threads 2# single输出
-4: 1

$ export OMP_NUM_THREADS=3
$ ./omp_nthrs_nesting
-1: 0
-1: 2
-1: 1
-2: 0 - 0
inner1: num threads 3
-2: 0 - 2
-2: 0 - 1
-2: 2 - 1
-2: 2 - 0
-2: 2 - 2
-2: 1 - 0
inner1: num threads 3
-2: 1 - 1
-2: 1 - 2
inner1: num threads 3
-3: 0 - 0
inner2: num threads 1
-3: 2 - 0
inner2: num threads 1
-3: 1 - 0
inner2: num threads 1
-4: 0
outter: num threads 3
-4: 1
-4: 2

运行环境函数

运行环境函数(Execution Environment Routines)是用于设置和获取 OpenMP 运行属性的函数,常用函数如下:

函数
说明
omp_set_num_threads(int)设置并行域中的线程个数(用在串行域中)
omp_get_num_threads()返回当前并行域中的线程个数
omp_get_max_threads()返回并行域中缺省可用的最大线程个数
omp_get_thread_num()返回当前线程的线程号,0号为主线程
omp_get_num_procs()返回系统中处理器的个数
omp_in_parallel()判断是否在并行域中
omp_set_dynamic(int)启用或关闭线程数目动态改变功能(用在串行域中)
omp_get_dynamic()判断系统是否支持动态改变线程数目
omp_set_nested(int)启用或关闭并行域嵌套功能(缺省为关闭)
omp_get_nested()判断系统是否支持并行域的嵌套

omp_set_dynamic 函数

函数 omp_set_dynamic 是启用或关闭线程数目动态改变功能,需要在串行域中调用。它可以使 num_threads 子句的设置失效。实例如下:

// desc: Interaction Between the num_threads Clause and omp_set_dynamic
// file: omp_nthrs_dynamic.1.cpp

#include <cstdio>
#include <omp.h>

int main(int argc, char const *argv[])
{
    omp_set_dynamic(1);
    // omp_set_dynamic(0);
    #pragma omp parallel num_threads(10)
    {
        int tid1 = omp_get_thread_num();
        printf("tid: %d\n", tid1);
    }

    return 0;
}

第 9 行调用 omp_set_dynamic(1) 支持动态改变线程数,输出如下:

$ export OMP_NUM_THREADS=3# 默认为3线程
$ ./omp_nthrs_dynamic.1# 运行时设为10个线程
tid: 3
tid: 2
tid: 0
tid: 6
tid: 4
tid: 5
tid: 1
tid: 7
tid: 9
tid: 8

若屏蔽第 9 行代码,放开第 10 行 omp_set_dynamic(0) ,不支持动态改变线程数,则输出如下:

$ ./omp_nthrs_dynamic.1
tid: 0
tid: 2
tid: 1

通过调用 omp_set_dynamic 函数显式设置 ICV( Internal Control Variables 内置控制变量,用于控制 OpenMP 程序行为的变量,比如存储线程数,线程号等信息) 是一种很好的做法,因为它的默认设置是由实现定义的,不同编译器都有各自的最优实现。


原文地址:https://blog.csdn.net/myw31415926/article/details/145267310

免责声明:本站文章内容转载自网络资源,如侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!