Archive

Posts Tagged ‘openmp’

OpenMP的初体验和问题的讨论

April 29th, 2009

今天小试了一下OpenMP,VS2005和08版都支持OpenMP。 在工程选项的语言栏启用OpenMP的支持,还要记得在文件里面添加, 如果忘记添加这个头文件,运行的时候会提示缺少vcompd.dll。
一个简单的使用OpenMP进行并行优化的程序如下:
#include <stdio.h>
#include <omp.h>

int main(int argc, char * argv[])
{
#pragma omp parallel for
for (int i = 0; i < 10; ++ i)
{
printf(”%d”, i);
}

getchar();
return 0;
}

第二个例子看起来是这样的:

#include <stdio.h>
#include <omp.h>
#include <ctime>

int main(int argc, char * argv[])
{
clock_t t1 = clock();
int sum = 0;
#pragma omp parallel for
for (int i = 0; i < 1000000; ++ i)
{
sum += sum;
}
printf(”\ntime:%d\n”, clock() - t1);

printf(”%d\n”, sum);

sum = 0;
for (int i = 0; i < 1000000; ++ i)
{
sum = (sum + i);
}

printf(”%d”, sum);
getchar();
return 0;

}

在跑这个程序的时候我发现启用了多线程for的程序所耗费的时间反而远远多于正常运行的时间。
注意到在循环中 sum是一个共享变量, 如果要在多线程中正确对其累加是要使用同步锁的。
实际运行会发现,累加的结果和实际的并不相符,也就是说OpenMP这里只是做了简单的分割。
而且由于伪共享的问题,会使得Cache失效,从而增加了运行时间。

正确的代码如下:

#include <stdio.h>
#include <omp.h>
#include <ctime>

int main(int argc, char * argv[])
{
clock_t t1 = clock();
int sum = 0;
#pragma omp parallel for reduction(+: sum)
for (int i = 0; i < 1000000; ++ i)
{
sum += sum;
}
printf(”\ntime:%d\n”, clock() - t1);

printf(”%d\n”, sum);

sum = 0;
for (int i = 0; i < 1000000; ++ i)
{
sum = (sum + i);
}

printf(”%d”, sum);
getchar();
return 0;
}

增加的reduction表示每个线程使用本地的sum进行操作,在并行代码块结束后进行reduction操作,reduction的语法是

reduction(operation:var)

这里我们使用+号作为operation, 即进行累加,这样修改过以后,程序达到了并行的效果,而且得到了正确的结果。

从这个问题我们可以看出并行程序设计和传统程序在思维上的不同,对于大多数习惯了串行程序的程序员来说,要写出正确的并行程序并不容易。

Author: gleery Categories: 程序设计 Tags: