我一直在介绍openmp示例和第一个多线程示例 - 对pi进行数值集成 - 我知道有关虚假共享的内容将会出现,所以实现了以下内容:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "omp.h"
#define STEPS 100000000.0
#define MAX_THREADS 4
void pi(double start, double end, double **sum);
int main(){
double * sum[MAX_THREADS];
omp_set_num_threads(MAX_THREADS);
double inc;
bool set_inc=false;
double start=omp_get_wtime();
#pragma omp parallel
{
int ID=omp_get_thread_num();
#pragma omp critical
if(!set_inc){
int num_threads=omp_get_num_threads();
printf("Using %d threads.\n", num_threads);
inc=1.0/num_threads;
set_inc=true;
}
pi(ID*inc, (ID+1)*inc, &sum[ID]);
}
double end=omp_get_wtime();
double tot=0.0;
for(int i=0; i<MAX_THREADS; i++){
tot=tot+*sum[i];
}
tot=tot/STEPS;
printf("The value of pi is: %.8f. Took %f secs.\n", tot, end-start);
return 0;
}
void pi(double start, double end, double **sum_ptr){
double *sum=(double *) calloc(1, sizeof(double));
for(double i=start; i<end; i=i+1/STEPS){
*sum=*sum+4.0/(1.0+i*i);
}
*sum_ptr=sum;
}
我的想法是,在使用calloc时,指针返回的概率是连续的,因此被拉入相同的缓存行几乎是不可能的(尽管我有点不确定为什么会有错误的共享无论如何,double是64位,我的缓存行也是8个字节,所以如果你能在那里启发我...)。 - 现在我意识到缓存行通常是64 bytes < / em>不是位
有趣的是,在编译之后我快速连续运行了程序,这是我得到的一个简短的例子(肯定是推动箭头并在终端输入超过1次/ .5秒):
user@user-kubuntu:~/git/openmp-practice$ ./pi_mp.exe
Using 4 threads.
The value of pi is: 3.14159273. Took 0.104703 secs.
user@user-kubuntu:~/git/openmp-practice$ ./pi_mp.exe
Using 4 threads.
The value of pi is: 3.14159273. Took 0.196900 secs.
我认为可能发生了一些事情,因为我试图避免错误分享的方式,因为我仍然对记忆水平之间的完整事件一无所知,我将其归结为此。所以,我按照教程的规定方法使用“关键”部分,如下所示:
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include "omp.h"
#define STEPS 100000000.0
#define MAX_THREADS 4
double pi(double start, double end);
int main(){
double sum=0.0;
omp_set_num_threads(MAX_THREADS);
double inc;
bool set_inc=false;
double start=omp_get_wtime();
#pragma omp parallel
{
int ID=omp_get_thread_num();
#pragma omp critical
if(!set_inc){
int num_threads=omp_get_num_threads();
printf("Using %d threads.\n", num_threads);
inc=1.0/num_threads;
set_inc=true;
}
double temp=pi(ID*inc, (ID+1)*inc);
#pragma omp critical
sum+=temp;
}
double end=omp_get_wtime();
sum=sum/STEPS;
printf("The value of pi is: %.8f. Took %f secs.\n", sum, end-start);
return 0;
}
double pi(double start, double end){
double sum=0.0;
for(double i=start; i<end; i=i+1/STEPS){
sum=sum+4.0/(1.0+i*i);
}
return sum;
}
运行时间加倍几乎相同。对此有何解释?它与低级内存有什么关系吗?你能回答我的中间问题吗?
非常感谢。
修改
编译器是Kubuntu 17.10上的gcc 7。使用的选项是-fopenmp -W -o(按此顺序)。
系统规格包括i5 6500 @ 3.2Ghz和16演出的DDR4 RAM(虽然我忘记了它的时钟速度)
正如有些人所说,如果连续两次运行超过两次,程序时间不会继续加倍。在初始加倍之后,它与我测试的连续运行次数大约相同(约.2秒)(5秒)。等待一两秒,运行时间返回到较小的数量。 但是,当运行不是连续手动运行而是在一个命令行中运行时,例如./pi_mp.exe;./pi_mp.exe;./pi_mp.exe;./pi_mp.exe;./pi_mp.exe;./pi_mp.exe;
我得到:
The value of pi is: 3.14159273. Took 0.100528 secs.
Using 4 threads.
The value of pi is: 3.14159273. Took 0.097707 secs.
Using 4 threads.
The value of pi is: 3.14159273. Took 0.098078 secs.
...
添加gcc优化选项(-O3)对任何结果都没有变化。