多线程使用1--#pragma omp parallel for

【1】属性设置

多线程使用1--#pragma omp parallel for_第1张图片

【2】使用方法

【1】基础方法

#pragma omp parallel for是OpenMP中的一个指令,表示接下来的for循环将被多线程执行,另外每次循环之间不能有关系。示例如下:

int main(int argc, char* argv[])

{
#pragma omp parallel for  //后面是for循环

     for (int i = 0; i < 10; i++ )

     {
         printf("i = %d/n", i);

     }

     return 0;

}

这个程序执行后打印出以下结果:

i = 0

i = 5

i = 1

i = 6

i = 2

i = 7

i = 3

i = 8

i = 4

i = 9

for循环里的内容必须满足可以并行执行,即每次循环互不相干,后一次循环不依赖于前面的循环。

【2】 竞态条件(race condition)的问题

当多个线程并行执行时,有可能多个线程同时对某变量进行了读写操作,从而导致不可预知的结果。

#include  
 int main()  
 {
 		int sum = 0; 
 		int a[10] = {1,2,3,4,5,6,7,8,9,10};
 		#pragma omp parallel for 
 		for (int i=0;i<10;i++) 
 			sum = sum + a[i]; 
 		std::cout<<"sum: "<<sum<<std::endl;
 		return 0;
 }

结果是49,而不是正确答案(55).
当某线程A执行sum = sum + a[i]的同时,另一线程B正好在更新sum,而此时A还在用旧的sum做累加,于是出现了错误。
除了尽量预先处理数据,避免race condition,解决方法之一就是归约(reduction)

【3】归约(reduction)

#include
#include
#include

int main(int argc,char *argv[])
{
    int sum=20;
    int thrdCnt=strtol(argv[1],NULL,10);
    //归约子句(归约操作符:归约变量)
#   pragma omp parallel num_threads(thrdCnt) reduction(+:sum)
    {
        int myRank=omp_get_thread_num();
        sum+=myRank;
        printf("%d->%d\n",myRank,sum);
    }
    printf("sum=%d\n",sum);//归约结果
    return 0;
}
9->9
1->1
2->2
3->3
4->4
7->7
8->8
5->5
0->0
6->6
sum=65

reduction(+:sum),它的意思是告诉编译器:下面的for循环你要分成多个线程跑,但每个线程都要保存变量sum的拷贝,循环结束后,所有线程把自己的sum累加起来作为最后的输出。reduction虽然很方便,但它只支持一些基本操作,比如+,-,*,&,|,&&,||等。
上述代码中,获取处理器的个数还可以这么做

#include 
 int coreNum = omp_get_num_procs();//获得处理器个数

另一个解决方法就是critical

【4】 critical


#include 
int main(){
    int max = 0;
    int a[10] = {11,2,33,49,113,20,321,250,689,16};
 #pragma omp parallel for
     for (int i=0;i<10;i++)
     {
         int temp = a[i];
 #pragma omp critical
         {
            if (temp > max)
                 max = temp;
         }
     }
     std::cout<<"max: "<<max<<std::endl;
     return 0;
 }

for循环还是被自动分成N份来并行执行,但我们用#pragma omp critical将 if (temp > max) max = temp 括了起来,它的意思是:各个线程还是并行执行for里面的语句,但当你们执行到critical里面时,要注意有没有其他线程正在里面执行,如果有的话,要等其他线程执行完再进去执行。这样就避免了race condition问题,但显而易见,它的执行速度会变低,因为可能存在线程等待的情况。

【3】OpenMP中的同步和互斥

(1)前言

在多线程编程中必须考虑到不同的线程对同一个变量进行读写访问引起的数据竞争问题。
OpenMP中有两种不同类型的线程同步机制,一种是互斥机制,一种是事件同步机制
互斥锁机制的设计思路是对一块共享的存储空间进行保护,保证任何时候最多只能有一个线程对这块存储空间进行访问,从而保证数据的完整性,这块存储空间称为“临界区”。可以通过critical、atomic等制导指令以及API中的互斥函数来实现。
事件同步机制的设计思路是控制线程的执行顺序,可以通过设置barrier同步路障、ordered定序区段、matser主线程执行等实现。

(2)互斥锁

待整理。

参考

https://www.cnblogs.com/yangyangcv/archive/2012/03/23/2413335.html
https://blog.csdn.net/bigfatcat_tom/article/details/98493040
http://blog.csdn.net/zhongkejingwang/article/details/40018735
https://www.cnblogs.com/mtcnn/p/9411890.html

你可能感兴趣的:(C++学习技术,多线程)