#include <math.h>
#include <stdlib.h>
#include <stdio.h>
#include <omp.h>
#define KE 10
#define NSTEPS 100
main()
{
float ex[KE],hy[KE];
float bn[NSTEPS];
int n,k,kc,ke;
float ddx,dt,T;
float t0,spread,pulse;
omp_set_num_threads(4);
kc = KE/2;
t0 = 40.0;
spread = 12;
T = 0;
FILE * temp = fopen("Exserial.txt", "w");
/* Initialize */
for ( k=0; k <= KE; k++ )
{
ex[k] = 0.0;
hy[k] = 0.0;
}
double strt=omp_get_wtime();
#pragma omp parallel shared(ex,hy,bn) private(n,k,T,pulse,t0,spread)
{
for ( n=1; n<=NSTEPS ; n++) {
T = T + 1;
pulse = exp(-.5*(pow( (t0-T)/spread,2.0) ));
ex[kc] = pulse;
/* Main FDTD Loop */
/* Calculate the Ex field */
#pragma omp critical
{
#pragma omp for
for ( k=1; k < KE; k++ )
{
#pragma omp atomic update
ex[k] = ex[k] + .5*( hy[k-1] - hy[k] ) ;
bn[n]=ex[100];
}
/* Calculate the Hy field */
#pragma omp for
for ( k=0; k < KE-1; k++ )
{
#pragma omp atomic update
hy[k] = hy[k] + .5*( ex[k] - ex[k+1] ) ;
}
}
}
}
double end=omp_get_wtime();
printf( "------------------%f\n",end-strt);
/* End of the Main FDTD Loop */
/* At the end of the calculation, print out the Ex and Hy fields */
for ( k=1; k <=KE; k++ )
{
fprintf(temp, "%f\n",ex[k]);
printf( "%f\n",ex[k]);
}
}
并行输出(使用的线程数= 4)
------------------0.013850
0.030408
-0.130364
0.107690
0.061082
0.023526
0.066983
-0.030821
-0.024117
0.037548
0.000000
串行输出
-0.013813
-0.028405
-0.044722
-0.064258
-0.087550
-0.072226
-0.062273
-0.055638
-0.052620
0.000000
我不知道我在哪里犯错,但是在并行程序中我得到了不同的结果。每次给出不同的输出。
还有一个问题,即当我从顶部删除#pragma omp parallel
时,我得到了正确的值,但是没有时间优势。我必须添加#pragma omp parallel
所以需要一些解决方案。
答案 0 :(得分:0)
按照@ 1201ProgramAlarm的建议,您正在进行一次数据竞赛。它在并行区域内和关键部分外包含以下语句:
ex[kc] = pulse;
每个线程都会在每次迭代时执行该操作,并且每个线程也会读回该值。读取位于关键部分内并不能将其保存为数据争用-写操作也必须也位于关键部分(不一定是同一部分),否则将受到某种形式的同步保护,以避免数据竞赛。
但是这里的问题是如此之大,以至于数据争用几乎是无关紧要的。 main 问题是循环迭代之间的计算具有很强的数据依赖性。也就是说,当串行运行时,外循环的每次迭代都会根据前一次迭代中计算出的值来更新ex
和hy
的所有元素。无论您进行多少同步或做出多大的决定性原因,如果您允许外部循环迭代以不同的顺序执行(如并行化),您就无法期望得到相同的结果(甚至一致的结果)。 / p>
这里的一线希望是,并行化无论如何也不会给您带来什么好处,因为外部循环执行的几乎所有工作都在关键部分。仅删除omp parallel
和omp critical
指令对改进此代码将有很长的路要走。对于这么小的KE
和如此简单的计算,也可能不留内部的omp for
,也没有什么意义,但是如果KE
非常 则可以考虑保留内部循环的并行化。