在OpenMP的for任务分担中,各个线程的任务划分是可以由程序员控制调整的。考虑这样一种情况,当在一个循环中每次迭代的计算量不相等时,如果根据系统默认简单的给每个线程分配相同次数的迭代量的话,会导致有些线程先执行玩,有些线程后执行完,造成CPU核的空闲,降低程序的运行效率。这种情况下就有必要人为的对各个线程的任务划分进行分配。

例如对如下的循环:

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

显然最后几次的计算量是远远大于前几次的计算量的,解决这种由于各个线程间均分迭代次数造成的负载不平衡的问题,可以通过schedule子句的使用来避免。

schedule子句的用法


使用格式:

schedule(type,size)

type表示调度类型,共有4种类型可选:

  • static
  • dynamic
  • guided
  • runtime

size参数定义了迭代次数最小的划分单位,每个线程依次分配size个迭代次数。

static静态调度


#include<iostream>
#include"omp.h" using namespace std; void main()
{
#pragma omp parallel for schedule(static,3)
for (int i = 0; i < 9; i++)
{
printf("i=%d, thread_id=%d\n", i, omp_get_thread_num());
}
system("pause");
}

输出:

从打印结果可以看出每个线程依次分配到3个连续的迭代计算。

dynamic动态调度


动态调度是动态的将迭代分配到各个线程上,可以使用size参数也可以不使用size参数,不适用size参数情况下size值默认为1,根据每个线程的完成情况每次再分配2个迭代给已完成迭代任务的线程,使用size参数则每次分配size个迭代次数。较快迭代完成的线程可能执行更多次迭代,较慢的线程执行较少的迭代,以此来解决各线程间负载分配不均衡的问题。

示例:

#include<iostream>
#include"omp.h" using namespace std; void main()
{
#pragma omp parallel for schedule(dynamic,2)
for (int i = 0; i < 12; i++)
{
printf("i=%d, thread_id=%d\n", i*i*i*i, omp_get_thread_num());
}
system("pause");
}

输出:

执行乘法运算,i比较小的时候计算量小,所以可以看到编号为0的线程执行了6次,编号为1、2和3的线程分别执行了2次。

guided调度


guided调度跟dynamic动态调度类似,是一种采用指导性的启发式自调度方法。刚开始时候每个线程会分配到较大的迭代块,之后每次分配到的迭代块会以指数级下降,直到下降到自定义的size大小,如果没有定义size,则默认为1。

runtime调度


runtime调度根据运行时的环境变量OMP_SCHEDULE来确定调度类型,最后还是会落实到schedule、dynamic和guided中的一种上来。

例如在unix系统中,可以使用setenv命令来设置OMP_SCHEDULE环境变量:

setenv OMP_SCHEDULE “dynamic, 2”

如果程序中选择runtime调度,那么上述命令设置调度类型为动态调度,动态调度的size为2。在windows环境中,可以在“系统属性|高级|环境变量”对话框中进行设置环境变量。

sections制导指令

for制导指令用于迭代计算的任务分配,sections制导指令用于非迭代计算的任务分配,sections的语法格式如下:

#pragma omp parallel sections[子句]

#include<iostream>
#include"omp.h" using namespace std; void main()
{
#pragma omp parallel sections
{
#pragma omp section
{
for (int i = 0; i < 4; i++)
{
printf("i=%d, thread_id=%d\n", i, omp_get_thread_num());
}
}
#pragma omp section
{ for (int i = 0; i < 4; i++)
{
printf("j=%d, thread_id=%d\n", i, omp_get_thread_num());
}
}
}
system("pause");
}

输出:

sections语句块中一共有2个section段落,所以生成了2个线程并行执行。

single制导指令

在parallel制导指令产生的并行域中的语句,一般会默认生成4个不同的线程对相同的语句分别执行一次,如果想要其中某些操作只执行一次,可以使用single制导指令,其后的语句块只会被单个线程执行。

#include<iostream>
#include"omp.h" using namespace std; void main()
{
#pragma omp parallel
{
#pragma omp single
{
printf("single thread_id=%d\n", omp_get_thread_num());
} printf("多线程执行,thread_id=%d\n", omp_get_thread_num());
}
system("pause");
}

输出:

由single引导的语句块只执行了一次,第二个printf语句没有single指令,所以被4个不同的线程分别执行了一次。

OpenMP编程的任务调度控制的更多相关文章

  1. openMP编程(下篇)之数据私有与任务调度

    title: openMP编程(下篇)之数据处理子句与任务调度 tags: ["openMP"] notebook: 分布式程序_Linux --- openMP并行编程中数据的共 ...

  2. 并行计算之OpenMP中的任务调度

    本文参考<OpenMP中的任务调度>博文,主要讲的是OpenMP中的schedule子句用法. 一.应用需求 在OpenMP并行计算中,任务调度主要用于并行的for循环.当for循环中每次 ...

  3. openMP编程(上篇)之指令和锁

    openMP简介 openMP是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的. 当计算机升级到多核时,程序中创建的线程数量需要随CPU核数变化,如在CPU核数超过线程数 ...

  4. openMP编程(上篇)之并行程序设计

    openMP简介 openMP是一个编译器指令和库函数的集合,主要是为共享式存储计算机上的并行程序设计使用的. 当计算机升级到多核时,程序中创建的线程数量需要随CPU核数变化,如在CPU核数超过线程数 ...

  5. 一个openMP编程处理图像的示例

    一个openMP编程处理图像的示例: 从硬盘读入两幅图像,对这两幅图像分别提取特征点,特征点匹配,最后将图像与匹配特征点画出来.理解该例子需要一些图像处理的基本知识,我不在此详细介绍.另外,编译该例需 ...

  6. Java编程基础——流程控制

    Java编程基础——流程控制 摘要:本文主要介绍Java编程中的流程控制语句. 分类 流程控制指的是在程序运行的过程中控制程序运行走向的方式.主要分为以下三种: 顺序结构:从上到下依次执行每条语句操作 ...

  7. OpenMP编程总结表

    本文对OpenMP 2.0的全部语法——Macro(宏定义).Environment Variables(环境变量).Data Types(数据类型).Compiler Directives(编译指导 ...

  8. Win32多线程编程(2) — 线程控制

    Win32线程控制只有是围绕线程这一内核对象的创建.挂起.恢复.终结以及通信等操作,这些操作都依赖于Win32操作系统提供的一组API和具体编译器的C运行时库函数.本篇围绕这些操作接口介绍在Windo ...

  9. Java并发编程:线程控制

    在上一篇文章中(Java并发编程:线程的基本状态)我们介绍了线程状态的 5 种基本状态以及线程的声明周期.这篇文章将深入讲解Java如何对线程进行状态控制,比如:如何将一个线程从一个状态转到另一个状态 ...

随机推荐

  1. Snail—UI学习之自己定义标签栏UITabBarController

    这里的背景跟上面的差点儿相同 watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkF ...

  2. 使用GDB进行嵌入式远程调试

    PC主机:Ubuntu 10.4 目标板:TQ2440开发板,linux内核2.6.30 NOTE:为了使用gdb进行调试,强烈建议使用nfs服务,否则调试会非常麻烦. 使用nfs服务可以参考:S3C ...

  3. 【Python排序搜索基本算法】之拓扑排序

    拓扑排序是对有向无环图的一种排序,满足例如以下两个条件: 1.每一个顶点出现且仅仅出现一次. 2.若A在序列中排在B的前面.则在图中不存在从B到A的路径. 如上的无环有向图,v表示顶点:v=['a', ...

  4. stm32的pwm波

  5. 对spring控制反转以及依赖注入的理解

    一.说到依赖注入(控制反转),先要理解什么是依赖. Spring 把相互协作的关系称为依赖关系.假如 A组件调用了 B组件的方法,我们可称A组件依赖于 B组件. 二.什么是依赖注入. 在传统的程序设计 ...

  6. 【35.20%】【CF 706D】Vasiliy's Multiset

    time limit per test 4 seconds memory limit per test 256 megabytes input standard input output standa ...

  7. Git恢复删除或修改的文件 ls-files

    一.git ls-files -d 查看删除了的文件 1.查看当前状态可以看到删除了一个index.js: git status image.png 2.查看当前项目中删除了的文件 git ls-fi ...

  8. [javase学习笔记]-7.5 构造函数须要注意的几个细节

    这一节我们简单的说几个在使用构造函数时须要注意的细节. 通过我们前几节的学习,我们对构造函数有了一个比較清楚的认识,当我们在创建对象时.我们会调用构造函数.那么我们在定义和调用构造函数时.须要注意哪些 ...

  9. 正則表達式基础及java使用

    正則表達式基础 正則表達式语法(1)     普通字符:字母,数字.汉子,下划线以及没有特殊定义的标点符号都是"普通字符".表达式中的普通字符.在匹配一个字符串的时候,匹配与之同样 ...

  10. 【t077】宝物筛选

    Time Limit: 1 second Memory Limit: 128 MB [问题描述] 小FF找到了王室的宝物室,里面堆满了无数价值连城的宝物--这下小FF可发财了.但是这里的宝物实在是太多 ...