我试图找到当我尝试使用openMP运行pi计算程序时出现错误的原因。
我正在使用的代码显示如下,使用vs2012并在项目中设置了openMP选项。我已成功运行hello world
程序,但我不明白这里的问题是什么。
#include <omp.h>
#include <stdio.h>
#include <stdlib.h>
#define NUM_THREADS 2
static long num_steps = 100000;
double step;
int main(void)
{
// Shared variable, updated !
int i;
double pi, sum[NUM_THREADS];
step = 1.0/(double) num_steps;
omp_set_num_threads(NUM_THREADS);
#pragma omp parallel
{ double x;
int id;
id = omp_get_thread_num();
sum[id]=0.0;
for (i=id; i< num_steps; i=i+NUM_THREADS){
x = (i+0.5)*step;
sum[id] += 4.0/(1.0+x*x);
}
}
pi=0.0;
for(i=0;i<NUM_THREADS;i++){
pi += sum[i] * step;
}
printf("pi = %f\n",pi);
return 0;
}
所以我得到的唯一错误是
pi.cpp(35): fatal error C1004: unexpected end-of-file found
这里发生了什么?这是Visual Studio的错误吗?
提前致谢
不介意代码效率低下,这里的问题不是关于这里的代码,而是VS2012和openMP ...
答案 0 :(得分:1)
默认情况下,预编译的标题功能处于启用状态。当它在每个cpp文件上时必须有第一个包含的行,如
#include "stdafx.h"
编译器正在扫描您的源文件以查找该行,并且在找到之前忽略其他所有内容。您可以在项目属性中关闭预编译的标题。
答案 1 :(得分:0)
您的问题基本上与另一个I answered recently重复。即使您获得编译代码后,您也会发现竞争条件和错误共享。我没有给出相同的答案,而是添加了新内容。
在您的代码中,您尝试为for循环手册定义块,另外还保存每个线程的部分和,然后在并行部分之后合并结果。对于你正在做的事情,没有充分的理由去做这些事情。但是,让我举两个你需要做的例子。我可以想到手动定义块的唯一原因是在执行induction to reduce the number of computations per iteration时。
在您的情况下,您可以将功能更改为使用感应,如下所示:
double pi = 0.0;
for(double x=0.5*step; x<max; x+=step) {
pi += 1.0/(1.0+x*x);
}
pi *= 4*step
要使用OpenMP执行此操作,需要定义for循环的开始和结束范围:
double pi = 0.0;
#pragma omp parallel reduction(+:pi)
{
int ithread = omp_get_thread_num();
int nthreads = omp_get_num_threads();
int start = ithread*n/nthreads;
int finish = (ithread+1)*n/nthreads;
double startx = (start+0.5)*step;
double finishx = (finish+0.5)*step;
for(double x=startx; x<finishx; x+=step) {
pi += 1.0/(1.0+x*x);
}
}
pi *= 4*step;
正如我已经说过的那样,感应是我能想到的唯一一个你需要做的事情。
您的代码还会保存每个线程减少的结果。我能想到这样做的唯一原因是你正在做的操作不是commutative。矩阵乘法不是可交换的,因为A*B
通常不等于到B*A
。但是你的操作是可交换的,但我们假设它不是。在这种情况下,你可以像这样做
double pi = 0.0;
int nthreads;
double *ppi;
#pragma omp parallel
{
double pi_private = 0.0;
int ithread = omp_get_thread_num();
#pragma single
{
nthreads = omp_get_num_threads();
ppi = new double[nthreads];
}
#pragma omp for
for(int i=0; i<n; i++) {
double x = (i+0.5)*step;
pi_private += 1.0/(1.0+x*x);
}
ppi[ithread] = pi_private;
}
for(int i=0; i<nthreads; i++) {
pi += ppi[i];
}
pi *= 4*step;
delete[] ppi;
顺便说一句,为了进行减少,操作需要是关联的。但浮点运算不是严格关联的。使用浮点运算进行简化时,必须接受结果可能无法再现。
无论如何,在你的情况下做的简单事情是:
double pi = 0.0;
#pragma omp parallel for reduction(+:pi)
for(int i=0; i<n; i++) {
double x = (i+0.5)*step;
pi += 1.0/(1.0+x*x);
}
pi *= 4*step;
这是完整的代码
include <stdio.h>
#include <omp.h>
void foo(int n) {
double step = 1.0/n;
double max = (0.5+n)*step;
double pi = 0.0;
for(double x=0.5*step; x<max; x+=step) {
pi += 1.0/(1.0+x*x);
}
pi *= 4*step;
printf("pi %f\n", pi);
}
void foo2(int n) {
double step = 1.0/n;
double pi = 0.0;
#pragma omp parallel reduction(+:pi)
{
int ithread = omp_get_thread_num();
int nthreads = omp_get_num_threads();
int start = ithread*n/nthreads;
int finish = (ithread+1)*n/nthreads;
double startx = (start+0.5)*step;
double finishx = (finish+0.5)*step;
for(double x=startx; x<finishx; x+=step) {
pi += 1.0/(1.0+x*x);
//printf("%d %f\n", ithread, x);
}
}
pi *= 4*step;
printf("pi %f\n", pi);
}
void foo3(int n) {
double step = 1.0/n;
double pi = 0.0;
int nthreads;
double *ppi;
#pragma omp parallel
{
double pi_private = 0.0;
int ithread = omp_get_thread_num();
#pragma single
{
nthreads = omp_get_num_threads();
ppi = new double[nthreads];
}
#pragma omp for
for(int i=0; i<n; i++) {
double x = (i+0.5)*step;
pi_private += 1.0/(1.0+x*x);
}
ppi[ithread] = pi_private;
}
for(int i=0; i<nthreads; i++) {
pi += ppi[i];
}
pi *= 4*step;
printf("pi %f\n", pi);
}
void foo4(int n) {
double step = 1.0/n;
double pi = 0.0;
#pragma omp parallel for reduction(+:pi)
for(int i=0; i<n; i++) {
double x = (i+0.5)*step;
pi += 1.0/(1.0+x*x);
}
pi *= 4*step;
printf("pi %f\n", pi);
}
int main() {
foo(1<<20);
foo2(1<<20);
foo3(1<<20);
foo4(1<<20);
}