炼数成金 门户 CUDA 查看内容

OpenMP多线程应用程序编程技术之线程同步

2015-9-11 13:50| 发布者: 炼数成金_小数| 查看: 2371| 评论: 0|原作者: beck_zhou|来自: CSDN

摘要: 在OpenMP应用程序中,由于是多线程执行,所以必须具有必要的线程同步机制来保证程序在出现数据竞争的时候能够得出正确的结果,并且在适当的时候控制线程的执行顺序。OpenMP支持两种不同类型的线程同步机制,一种是互 ...

编程 编程技术

2.3.3线程同步
在OpenMP应用程序中,由于是多线程执行,所以必须具有必要的线程同步机制来保证程序在出现数据竞争的时候能够得出正确的结果,并且在适当的时候控制线程的执行顺序。OpenMP支持两种不同类型的线程同步机制,一种是互斥锁的机制,另外一种同步机制是事件通知机制。互斥的操作针对需要保护的数据而言,在产生了数据竞争的内存区域加入互斥,包括critical、atomic等语句以及函数库中的互斥函数。而事件机制则控制规定线程执行顺序时所需要的同步屏障。

1.  互斥锁机制
在OpenMP中,提供了三种不同的互斥锁机制,用来对一块内存进行保护,它们分别是临界区、原子操作(atomic)以及由库函数提供的同步操作。

(1)临界区
临界区通过编译指导语句对产生数据竞争的内存变量进行保护。在程序需要访问可能产生竞争的内存数据时,都需要插入相应的临界区代码。临界区编译指导语句的格式为:
      #pragma omp critical [(name)]
        block
在执行程序块block之前,必须先获得临界区的控制权,在多线程执行时,OpenMP会保证每次最多只有一个线程执行临界区,name是临界区的名字。临界区的使用如下例所示。

代码片段2_1
// 将数组ar中的较大值取出赋值给变量max
#pragma omp parallel for
for(i=0;i<100;i++)
{  #pragma omp critical
   if(ar[i]>max)  max = ar[i];
}
(2)原子操作
原子操作是OpenMP编程方式给同步编程带来的特殊的功能。通过一条指令就能够完成数据的读取与更新操作,原子操作在执行过程中是不会被打断的。因此这种方式提供了一种更高效的互斥锁机制。在OpenMP这种功能是通过编译指导语句#pragma omp atomic提供的,原子操作如下所示:
代码片段2_2
       #pragma omp parallel
          { for(int i=0;i<10000;i++)
         #pragma omp atomic
                     counter++;
          }
输出结果为:
counter=20000
当使用atomic语句时,执行结果是20000(两个线程进行并行区域运算,counter自加20000次);当不使用atomic语句时,程序会产生数据竞争,例如counter当前值为100,当线程0执行counter+1操作后,线程0挂起,线程1执行counter+1并赋值操作,这时counter值是101,现在继续线程0的操作,它将刚执行完的加法操作的结果(101)赋值给counter,counter最后的值为101,显然结果是不正确的。

(3)运行时库函数的互斥锁支持
除了critical、atomic编译语句外,OpenMP还通过一系列库函数支持更加细致的互斥操作。表2-1列出了OpenMP函数库提供的互斥锁函数。

函数名称

描述

void omp_init_lock(omp_lock_t *)

初始化一个互斥锁

void omp_destroy_lock(omp_lock_t *)

结束一个互斥锁的使用并释放内存

void omp_set_lock(omp_lock_t *)

获得一个互斥锁

void omp_unset_lock(omp_lock_t *)

释放一个互斥锁

int omp_test_lock(omp_lock_t *)

试图获得一个互斥锁,并在成功时返回真,失败时返回假

表 2-1
互斥锁函数的使用比起编译指导语句更加灵活。编译指导语句进行的互斥锁支持只能放置在一段代码之前,作用在这段代码之上,使用函数的互斥锁支持则可以将函数放置在程序员所需的任意位置。

2.    同步屏障语句
在并行执行的时候,有些情况下需要程序员插入同步屏障语句#pragma omp barrier。此时,在并行区域的执行过程中,所有的执行线程都会在同步屏障语句上进行同步。
#pragma omp parallel
    {   initialization();
#pragma omp barrier
        process();
}
在上面例子中,只有等所有线程都完成初始化操作后,才能进行下一步的处理。

鲜花

握手

雷人

路过

鸡蛋

最新评论

热门频道

  • 大数据
  • 商业智能
  • 量化投资
  • 科学探索
  • 创业

即将开课

热门文章

     

    GMT+8, 2020-1-21 19:01 , Processed in 0.116365 second(s), 23 queries .