炼数成金 门户 CUDA 查看内容

OpenMP: OpenMP同步构造

2015-9-11 14:35| 发布者: 炼数成金_小数| 查看: 1259| 评论: 0|原作者: Augusdi|来自: CSDN

摘要: OpenMP用于并行编程,自然,就会有“数据竞争”等相关问题。所以,OpenMP也提供了一些同步构造的指令,用于进行同步(synchronization)。指令功能:master指令指定一个区域只会被一个team中的主线程(master thread ...

编程

同步构造:Synchronization Constructs
(1)什么是同步构造?
OpenMP用于并行编程,自然,就会有“数据竞争”等相关问题。所以,OpenMP也提供了一些同步构造的指令,用于进行同步(synchronization)。

(2)同步构造之master指令
指令功能:master指令指定一个区域只会被一个team中的主线程(master thread)执行,team内的其他线程都会忽略此区域。此指令没有隐含的等待。
指令格式:
[cpp] view plaincopy
#pragma omp master  newline    
   structured_block  
指令限制:master指令不允许跳出或跳进(goto等)master块。

(3)同步构造之critical指令
指令功能:critical指令指定某一区域的代码每次只能同时被一个线程执行。

指令格式:
[cpp] view plaincopy
#pragma omp critical [ (name) ]  newline    
   structured_block  
指令限制:critical指令不允许跳出或跳进(goto等)critical块。

说明:
如果一个执行正在执行critical块的代码,并且其他线程也达到了critical块,那么这个线程会阻塞等待,直到第一个线程执行完critical的代码。其实,critical就相当于简化的win32多线程中的临界区或锁的概念。
实例:
[cpp] view plaincopy
#include    
int g;    
#define ADD_COUNT   100000    
    
int main(int argc, char *argv[])    
{    
    printf("Masterthread started\n\n");    
    
#pragma omp parallel    
    {    
        for (int i = 0; i < ADD_COUNT;i ++)    
        {    
#pragma omp critical    
            g = g + 1;      // Will cause data races without critical directive.    
        }    
    }// End of parallel region    
    
    printf("g = %d\n", g);    
    printf("Expected g = %d\n",ADD_COUNT * 4);        // Assume the thread number is 4.    
    
    printf("Masterthread finished\n");    
    
    return(0);    
}    
这里,如果不使用critical,得到的结果将会不正确,就是由于数据竞争引起的。
下面的例子是同样的数据竞争的例子,这两个例子比较一下也可以加深对parallel和parallel for的区别。
[cpp] view plaincopy
#include    
int g;    
#define ADD_COUNT   1000000    
    
int main(int argc, char *argv[])    
{    
    printf("Masterthread started\n\n");    
    
#pragma omp parallel for    
        for (int i = 0; i < ADD_COUNT;i ++)    
        {    
#pragma omp critical    
            g = g + 1;      // Will cause data races without critical directive.    
        } // End of parallel for region    
    
    printf("g = %d\n",g);    
    printf("Expected g = %d\n", ADD_COUNT);    
    
    printf("Masterthread finished\n");    
    
    return(0);    
}    
关于name选项:在critical中,还有一个name的参数,critical可以指定代码段的name,同一个name的代码段被当成同一个代码段,所有未命名的代码段都当作一个代码段。
下面的两个例子对比来理解name的作用:
[cpp] view plaincopy
#include    
int g;    
int g1;    
#define ADD_COUNT   1000000    
    
int main(int argc, char *argv[])    
{    
    printf("Masterthread started\n\n");    
    
#pragma omp parallel for    
        for (int i = 0; i < ADD_COUNT;i ++)    
        {    
#pragma omp critical (namex)    
            g = g + 1;          // Will cause data races without critical directive.    
    
#pragma omp critical (namey)    
            g1 = g1 + 1;        // Will cause data races without critical directive.    
        } // End of parallel for region    
    
    printf("g = %d, g1 = %d\n",g, g1);    
    printf("Expected g = g1 = %d\n", ADD_COUNT);    
    
    printf("Masterthread finished\n");    
    
    return(0);    
}    
这个例子定义了两个全局变量g和g1,分别运算,所以可以使用两个critical进行同步,那么第一个线程在操作namex段的代码(g)的时候,另一个线程(第二个线程)可能在等待,然后,第一个线程进入namey代码段,那么此时第二个线程就可以执行namex段的代码了,由于分别是g和g1的操作,这样是完全允许同时进行的。然而,下面的例子,使用不同的命名的critical,就会导致结果错误:
[cpp] view plaincopy
#include    
int g;    
int g1;    
#define ADD_COUNT   1000000    
    
int main(int argc, char *argv[])    
{    
    printf("Masterthread started\n\n");    
    
#pragma omp parallel for    
    for (int i = 0; i < ADD_COUNT;i ++)    
    {    
#pragma omp critical (namex)    
        g = g + 1;    
    
#pragma omp critical (namey)    
        g = g + 1;          // Still data races!            
    } // End of parallel for region    
    
    g1 = g;    
    printf("g = %d, g1 = %d\n",g, g1);    
    printf("Expected g = g1 = %d\n",ADD_COUNT);    
    
    printf("Masterthread finished\n");    
    
    return(0);    
}   

(4)同步构造之barrier指令
指定作用:barrier是最简单的同步指令了,用于同步team中的所有线程。当一个线程达到了barrier后,它会在此处等待知道其它所有线程都执行到此处。
指令格式:
[cpp] view plaincopy
#pragma omp barrier  newline    

(5)同步构造之taskwait指令
OpenMP3.0新增加的指令,和task构造指令相关。

(6)同步构造之atomic指令
指令作用:指定某一内存位置必须原子操作的形式更新。相当于简化的critical的使用。
指令格式:
[cpp] view plaincopy
#pragma omp atomic  newline    
   statement_expression    
说明:atomic后面不是一个structed bock,而是一个表达式。atomic的使用有一些格式要求,具体参考OpenMP spec说明。

(7)同步构造之flush指令
指令作用:指定一个同步点,在此处,线程变量会写入到真实的内存中去。
指令格式:
[cpp] view plaincopy
#pragma omp flush (list)  newline    

(8)同步构造之ordered指令
指定for循环迭代和串行一样的顺序执行。
只能用于指令了ordered子句的for指令。
指令格式:
[cpp] view plaincopy
#pragma omp for ordered [clauses...]    
   (loop region)    
#pragma omp ordered  newline    
   structured_block    
   (endo of loop region)    

说明:
对于基本的使用,master,critical,barrier指令需要掌握和理解,其他指令,在以后逐步理解。

鲜花

握手

雷人

路过

鸡蛋

最新评论

热门频道

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

即将开课

热门文章

     

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