OpenMP并行程序设计之常用子句使用介绍(二)

OpenMP并行程序设计之常用子句使用介绍(二)
    承接上面的博客,这次还要介绍三个OpenMP并行程序设计的数据处理子句,threadprivate子句,reduction子句以及sections子句。

1.  threadprivate子句

    这个子句理解较为简单,作用呢,就是对于一些全局变量,可以使用这条指令,使得每一个线程都能有此全局变量的独立的拷贝,并且互相不影响。需要注意的是,该指令所指示的一定是全局变量,即在全程序是有效的,而且是永久变量,在多个并行域内都有效。我们代码走起。

#include<iostream>
#include <omp.h>  
int g;//全局变量

#pragma omp threadprivate(g)  //声明变量线程私有
int main(int argc, char *argv[])
{
	/* Explicitly turn off dynamic threads */
	//omp_set_dynamic(0);

	printf("Masterthread started\n\n");

#pragma omp parallel  
	{
		g = omp_get_thread_num();
		printf("tid: %d\n", g);
	} // End of parallel region  

#pragma omp parallel  
	{
		int temp = g*g;
		printf("tid : %d, tid*tid: %d\n", g, temp);
	} // End of parallel region  

	printf("Masterthread finished\n");
	system("pause");
	return(0);
	
}
程序运行结果如下:



    从上面的程序以及运行结果可以看出,有两个并行域,两个并行域共享全局变量g,而且在各自并行域中各个线程共享变量g,但是在各个线程中g值的输出是互不影响的,是相互独立的。


2.   reduction子句

    在介绍这个子句之前,请先看下面示例

#include <iostream>  
void test()
{
	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;
}
int main()
{
	for (int i = 0; i < 10; i++)
		test();
	system("pause");
	return 0;
}
程序运行结果如下:

    诶,为什么会出现这样的运行结果呢,按理来说,每次执行test()函数,得到的sum的求和值应该都是55啊,为啥还会出现27,47,40,42呢。之所以会出现上述错误的输出结果就是因为存在数据竞争的问题。这应该是所有多线程编程中最为棘手的问题了,那么对于这样的并行处理求和该怎么办呢,reduction子句就能派上用场。我们对上面的代码做一些小的修改,我们在#pragma omp parallel for 后面加上了 reduction(+:sum)。代码如下:

#include <iostream>  
void test()
{
	int sum = 0;
	int a[10] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
#pragma omp parallel for  reduction(+:sum)
	for (int i = 0; i < 10; i++)
		sum = sum + a[i];
	std::cout << "sum: " << sum << std::endl;
}
int main()
{
	for (int i = 0; i < 10; i++)
		test();
	system("pause");
	return 0;
}
程序运行结果如下:



   从上面的运行结果可以看出,所有结果都是正确的。reduction(+:sum)它的意思是告诉编译器:下面的for循环你要分成多个线程跑,但每个线程都要保存变量sum的拷贝,循环结束后,所有线程把自己的sum累加起来作为最后的输出。

3.   section子句和sections子句

    section语句是用在sections语句里用来将sections语句里的代码划分成几个不同的段,每段都并行执行。用法如下:

#pragma omp [parallel] sections [子句]
{
   #pragma omp section
   {
            代码块
   } 
}

下面我们来看个实例吧,代码最具有说服力,最能让人理解。

#include <iostream>  
#include<omp.h>
int main(int argc, char *argv)
{
#pragma omp parallel sections
	{
#pragma omp section
		printf("section 1 ThreadId = %d\n", omp_get_thread_num());
#pragma omp section 
		printf("section 2 ThreadId = %d\n", omp_get_thread_num());
#pragma omp section
		printf("section 3 ThreadId = %d\n", omp_get_thread_num());
#pragma omp section 
		printf("section 4 ThreadId = %d\n", omp_get_thread_num());
	}
	system("pause");
	return 0;
}

程序运行结果如下:



    从结果中可以发现第3段代码执行比第2段代码早,说明各个section里的代码都是并行执行的,并且各个section被分配到不同的线程执行。使用section语句时,需要注意的是这种方式需要保证各个section里的代码执行时间相差不大,否则某个section执行时间比其他section过长就达不到并行执行的效果了

    上面的代码也可以改写成以下形式:

#include <iostream>  
#include<omp.h>
int  main(int argc, char *argv)
{
#pragma omp parallel
	{
#pragma omp sections//sections 1
		{
#pragma omp section
			printf("section 1 ThreadId = %d\n", omp_get_thread_num());
#pragma omp section
			printf("section 2 ThreadId = %d\n", omp_get_thread_num());
		}
#pragma omp sections
		{

#pragma omp section//sections 2
		printf("section 3 ThreadId = %d\n", omp_get_thread_num());
#pragma omp section
		printf("section 4 ThreadId = %d\n", omp_get_thread_num());
	}
	}
	system("pause");
	return 0;
}

程序运行结果:



   这种方式和前面那种方式的区别是,两个sections语句是串行执行的,即第二个sections语句里的代码要等第一个sections语句里的代码执行完后才能执行。个人认为OpenMP并行程序设计比较常用的数据子句也就这些,当然还有其他子句了,比如copyin,default等等。








参考文献:
http://blog.csdn.net/gengshenghong/article/details/6969957
http://blog.csdn.net/wangzhebupt/article/details/22743515

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值