zoukankan      html  css  js  c++  java
  • OpenMP模式下多线程文件操作(四)

    线程同步之互斥锁函数

    前文介绍了互斥锁同步的两种方法:atomic和critical,本章介绍OpenMP提供的互斥锁函数。互斥锁函数类似于Windows、Linux下的mutex。

    1. 互斥锁函数

      函数声明                                                                   功能

      void omp_init_lock(omp_lock*)                               初始化互斥器

      void omp_destroy_lock(omp_lock*)                        销毁互斥器

      void omp_set_lock(omp_lock*)                               获得互斥器

      void omp_unset_lock(omp_lock*)                           释放互斥器

      void omp_test_lock(omp_lock*)                              试图获得互斥器,如果获得成功则返回true,否则返回false

    2. 互斥锁示例

       

    ·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
    1. #include <iostream>   
    2. #include <omp.h>   
    3.   
    4. static omp_lock_t lock;  
    5.   
    6. int main()  
    7. {  
    8.    omp_init_lock(&lock); //初始化互斥锁   
    9.   
    10. #pragma omp parallel for   
    11.    for(int i = 0; i < 5; ++i)  
    12.    {  
    13.       omp_set_lock(&lock);   //获得互斥器   
    14.        std::cout << omp_get_thread_num() << "+" << std::endl;  
    15.       std::cout << omp_get_thread_num() << "-" << std::endl;  
    16.       omp_unset_lock(&lock); //释放互斥器   
    17.     }  
    18.   
    19.    omp_destroy_lock(&lock);  //销毁互斥器   
    20.     return 0;  
    21. }  

    上边的示例对for循环中的所有内容进行加锁保护,同时只能有一个线程执行for循环中的内容。

    线程1或线程2在执行for循环内部代码时不会被打断。如果删除代码中的获得锁释放锁的代码,则相当于没有互斥锁。

    互斥锁函数中只有omp_test_lock函数是带有返回值的,该函数可以看作是omp_set_lock的非阻塞版本。

    线程同步之事件同步机制

    1. 引言

    前边已经提到,线程的同步机制包括互斥锁同步和事件同步。互斥锁同步包括atomic、critical、mutex函数,其机制与普通多线程同步的机制类似。而事件同步则通过nowait、sections、single、master等预处理指示符声明来完成。

    2. 隐式栅障

          在开始之前,先介绍一下并行区域中的隐式栅障。

          栅障(Barrier)是OpenMP用于线程同步的一种方法。线程遇到栅障时必须等待,直到并行的所有线程都到达同一点。

          注意:

          在任务分配for循环和任务分配section结构中隐含了栅障,在parallel, for, sections, single结构的最后,也会有一个隐式的栅障。

    隐式的栅障。

          隐式的栅障会使线程等到所有的线程继续完成当前的循环、结构化块或并行区,再继续执行后续工作。可以使用nowait去掉这个隐式的栅障。

    3. nowait事件同步

        nowait用来取消栅障,其用法如下:

        #pragma omp for nowait  //不能使用#pragma omp parallel for nowait

        或

        #pragma omp single nowait

        示例:

       

    ·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
    1. #include <iostream>   
    2. #include <omp.h>   
    3.   
    4. int main()  
    5. {  
    6.     #pragma omp parallel   
    7.    {  
    8.       #pragma omp for nowait   
    9.       for(int i = 0; i < 1000; ++i)  
    10.       {  
    11.          std::cout << i << "+" << std::endl;  
    12.       }  
    13.   
    14.       #pragma omp for   
    15.       for(int j = 0; j < 10; ++j)  
    16.       {  
    17.          std::cout << j << "-" << std::endl;  
    18.       }  
    19.    }  
    20.    return 0;  
    21. }  

    运行程序,可以看到第一个for循环的两个线程中的一个执行完之后,继续向下执行,因此同时打印了第一个循环的+和第二个循环的-。

    如果去掉第一个for循环的nowait生命,则第一个for循环的两个线程都执行完之后,才开始同时执行第二个for循环。也就是说,通过#pragma omp for声明的for循环结束时有一个默认的隐式栅障。

    4. 显示同步栅障 #pragma omp barrier

         

    ·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
    1. #include <iostream>   
    2. #include <omp.h>   
    3.   
    4. int main()  
    5. {  
    6.     #pragma omp parallel   
    7.     {  
    8.         for(int i = 0; i < 100; ++i)  
    9.         {  
    10.             std::cout << i << "+" << std::endl;  
    11.         }  
    12.           
    13.         #pragma om barrier   
    14.         for(int j = 0; j < 10; ++j)  
    15.         {  
    16.             std::cout << j << "-" << std::endl;  
    17.         }  
    18.     }  
    19.   
    20.     return 0;  
    21. }  

    运行程序,可以看出两个线程执行了第一个for循环,当两个线程同时执行完第一个for循环之后,在barrier处进行了同步,然后执行后边的for循环。

    5. master事件同步

        通过#pragma om master来声明对应的并行程序块只有主线程完成。

       

    ·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
    1. #include <iostream>   
    2. #include <omp.h>   
    3.   
    4. int main()  
    5. {  
    6. #pragma omp parallel   
    7. {  
    8.    #pragma omp master   
    9.    {  
    10.       for(int j = 0; j < 10; ++j)  
    11.       {  
    12.          std::cout << j << "-" << std::endl;  
    13.       }  
    14.    }  
    15.   
    16.    std::cout << "This will printed twice." << std::endl;  
    17. }  
    18.    return 0;  
    19. }  

    运行程序,可以看到,进入parallel声明的并行区域之后,创建了两个线程。主线程执行了for循环,而另一个线程没有执行for循环,而直接进入了for循环之后的打印语句,然后执行for循环的线程随后还会再执行一次后边的打印语句。

    6. sections用来指定不同的线程执行不同的部分

        下面通过一个实例来说明其使用方法:

        

    ·········10········20········30········40········50········60········70········80········90········100·······110·······120·······130·······140·······150
    1. #include <iostream>   
    2. #include <omp.h>   
    3.   
    4. int main()  
    5. {  
    6.   
    7. //声明该并行区域分为若干个section,section之间的运行顺序为并行   
    8. //的关系   
    9. #pragma omp parallel sections   
    10.    for(int i = 0; i < 5; ++i)  
    11.    {  
    12.        std::cout << i << "+" << std::endl;  
    13.    }  
    14.   
    15. #pragma omp section   //第一个section,由某个线程单独完成   
    16.     for(int j = 0; j < 5; ++j)  
    17.    {  
    18.        std::cout << j << "-" << std::endl;  
    19.    }  
    20.   
    21.    return 0;  
    22. }  

    可以看到,并行区域中有两个线程,所以两个section同时执行。

  • 相关阅读:
    第1章:程序设计和C语言(C语言入门)
    倒计时IE6+
    uploadify 使用 详细 说明
    HTTP&#160;错误
    asp.net 向后台提交 html 代码段 包括 <> 标签
    C#使用NLog记录日志
    IE浏览器 location.href 不跳转
    .Net Core 导出Excel
    .net mvc 获取acion 返回类型
    sql sever 执行较大的文件脚本
  • 原文地址:https://www.cnblogs.com/BIGFOOT/p/2162232.html
Copyright © 2011-2022 走看看