美文网首页
OpenMP笔记

OpenMP笔记

作者: delta1037 | 来源:发表于2019-05-20 20:35 被阅读0次

    进程与线程

    进程:进程是正在运行的程序实例
    线程:线程是进程中实际运作单位,一个进程可以并行多个线程

    进程包含如下程序资源和程序执行状态信息:
    进程ID/环境/工作目录/程序指令/寄存器/栈/堆/文件描述符/信号动作/共享库/进程间通信工具(消息队列,管道,信号量,共享内存)

    线程使用和在进程中生存,仍有操作系统来安排并且独立的实体来运行,很大程度上是因为他们为可执行代码的存在复制了刚刚好的基本资源

    这个独立的控制流之所以实现,是因为线程维护着:
    栈指针/寄存器/调度属性(规则和优先级)/等待序列和阻塞信号/线程拥有的数据

    Unix环境中线程的特点:
    生存在进程中,并使用进程资源
    拥有独立的控制流,前提是它的父进程还存在,并且操作系统支持它
    它仅仅复制可以使他调度的必要的资源
    他可能会同其它与之同等独立的线程分享进程资源
    如果父进程死掉那么它也会死掉
    它是轻量级的,因为大部分的开支已经在它的进程创建时完成了

    由于在同一个进程内的线程分享资源:
    一个线程对共享的系统资源做出改变会被其它线程看到
    指向同一个地址的两个指针的数据是相同的
    对同一块内存进行读写操作是可行的,但是需要程序员明确的同步处理操作

    OpenMP是MultiProcessing的缩写
    作为框架或者说协议:
    OpenMP并不是一个简单的函数库,而是一个诸多编译器支持的框架,或者是协议,不需要任何配置

    在编译程序时在末尾加上-fopenmp

    循环的并行化:
    OpenMP提供一种简单的方式让人们不需要懂得创建和销毁线程就能写出来多线程的程序,为此设计了一些pragma,指令和函数让编译器在合适的地方插入线程太多的循环只要在for之前插入一个pragma就可以了

    #pragma omp parallel for
    每个循环被分配都被分配到了不同的线程,并且保证只执行一次,OpenMP决定了多少线程要打开,销毁和创建,需要做的就是告诉OpenMP哪里需要被线程化

    OpenMP对多线程化的循环的要求:
    循环的变量值必须是有符号整形
    循环的比较条件必须是< <= > >=中的一种
    循环的增量部分必须是增减一个不变的值
    如果比较的符号是< <=,那么每次循环变量应该增加,反之减小
    循环必须没有奇奇怪怪的东西,不能从内部循环跳到外部循环,goto和break只能在循环内部跳转,异常必须在循环内部被捕获

    检测是否支持OpenMP:
    #ifndef _OPENMP
    fprintf(stderr,"OpenMP not supported");
    #endif

    避免数据依赖和竞争:
    两个不同的迭代之间不能有依赖关系
    当每次迭代都依赖于另一个不同的迭代,这被称为竞态条件
    竞态条件很难被检测到

    管理公有和私有数据:
    当数据被设置为私有的时候,每个线程都有自己的一份拷贝
    当数据被设置为公有的时候,所有的线程访问的都是相同的内存地址
    默认情况下:除了循环变量以外,所有的数据都被设置为公有的

    把变量设置为私有的方法:
    在循环内部声明变量,注意不要是static的
    通过OpenMP指令声明私有变量:#pragma cmp parallel for private(temp)

    Reductions:
    一种常见的循环就是累加变量,循环内部有sum+=arry[i];
    为此OpenMP提供了reductions语句:#pragma cmp parallel for reductions是(+:sum)
    在内部实现中,OpenMP为每个线程提供了私有的sum变量,当线程退出时,OpenMP再把每个线程的和加在一起得到最终结果

    OpenMP不只能做累加,凡是累计计算都是可以的:
    操作 私有临时变量初值
    +,- 0
    × 1
    & ~0
    | 0
    ^ 0
    && 1(true)
    || 0(false)

    循环调度:
    负载均衡是多线程程序中对性能影响最大的因素,只有实现负载均衡才能保证所有的核心都是忙的,而不会出现空闲时间,若没有达到负载均衡,一些线程早于其它线程结束,导致处理器空闲浪费优化的性能

    在循环中由于每次迭代的时间差太大破坏负载均衡
    默认情况下,OpenMP认为所有的循环迭代的运行时间都是一样的,导致了OpenMP会把不同的迭代等分到不同的核心上,并且让他们的分布尽可能地减少内存冲突,这样做是因为循环一般会线性的访问内存,所以把循环按照前一半后一半的方法分配可以最大程度来减少冲突,这最内存访问来说是最好的方法,但是对于负载均衡可能不是最好的方法,反过来最好的负载均衡可能也会破坏内存的访问,需要折中考虑

    OpenMP负载均衡语法:
    #pragma omp parallel for schedule(kind[,chunk size])
    kind 的类型,chunk size必须是循环不变的正整数

    相关文章

      网友评论

          本文标题:OpenMP笔记

          本文链接:https://www.haomeiwen.com/subject/hnvlzqtx.html