OpenMP使用的一些陷阱

问题引入

我在写代码的过程中发现使用OpenMP后反而运行速度更慢了,后来查了许多资料发现一些其他的使用陷阱,总结了这篇博文

问题一:临界变量

#include <omp.h>
#include <stdio.h>
int main(){
    int sum=0;
    #pragma omp parallel for num_threads(6)
    for(int i=0;i<100;i++){
        sum+=i;
    }
    printf("%d\n",sum);
}

输出:

2892

为什么不是4950呢,因为sum是临界变量,当多个线程同时对sum写时会相互覆盖。
解决方案
(1)在临界区添加#pragma omp critical

#include <omp.h>
#include <stdio.h>
int main(){
    int sum=0;
    #pragma omp parallel for num_threads(6)
    for(int i=0;i<100;i++){
        #pragma omp critical
        {
            sum+=i;
        }
        
    }
    printf("%d\n",sum);
}

(2)在#pragma omp parallel指令中添加reduction子句,并指定要进行归约的操作和变量。

#include <omp.h>
#include <stdio.h>
int main(){
    int sum=0;
    #pragma omp parallel for num_threads(6) reduction(+:sum)
    for(int i=0;i<100;i++){
            sum+=i;
    }
    printf("%d\n",sum);
}

在这个例子中,reduction子句指定了对变量sum进行加法归约操作。
归约操作就是指满足结合律和交换律的操作例如

 + - * & | ^ max min 

都是归约操作。

对于只是归约操作而言方案(2)相对来说更好,方案(1)临界区定义会使得只有一个线程进入临界区,其他线程等待,减慢了速度。
但是对于其他非归约操作,访问临界区需要方案(1)来解决。

问题二:变慢陷阱

	int i,j;
	#pragma omp parallel for
	for(i = 0; i < divs*divs; ++i){
		data d;
		d.shallow = 0;
		d.w = orig.w/divs * size;
		d.h = orig.h/divs * size;
		d.X.rows = orig.X.rows;
		d.X.cols = d.w*d.h*3;
		d.X.vals = calloc(d.X.rows, sizeof(float*));

		d.y = copy_matrix(orig.y);
		#pragma omp parallel for
		for(j = 0; j < orig.X.rows; ++j){
			int x = (i%divs) * orig.w / divs - (d.w - orig.w/divs)/2;
			int y = (i/divs) * orig.h / divs - (d.h - orig.h/divs)/2;
			image im = float_to_image(orig.w, orig.h, 3, orig.X.vals[j]);
			d.X.vals[j] = crop_image(im, x, y, d.w, d.h).data;
		}
		ds[i] = d;
	}

虽然全部核心都被使用但是速度反而比单核时慢,因为提前定义了i和j
解决方案


	#pragma omp parallel for
	for(int i = 0; i < divs*divs; ++i){
		data d;
		d.shallow = 0;
		d.w = orig.w/divs * size;
		d.h = orig.h/divs * size;
		d.X.rows = orig.X.rows;
		d.X.cols = d.w*d.h*3;
		d.X.vals = calloc(d.X.rows, sizeof(float*));

		d.y = copy_matrix(orig.y);
		#pragma omp parallel for
		for(int j = 0; j < orig.X.rows; ++j){
			int x = (i%divs) * orig.w / divs - (d.w - orig.w/divs)/2;
			int y = (i/divs) * orig.h / divs - (d.h - orig.h/divs)/2;
			image im = float_to_image(orig.w, orig.h, 3, orig.X.vals[j]);
			d.X.vals[j] = crop_image(im, x, y, d.w, d.h).data;
		}
		ds[i] = d;
	}
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值