gpt4 book ai didi

c - OpenMP 段错误

转载 作者:太空宇宙 更新时间:2023-11-04 03:14:09 48 4
gpt4 key购买 nike

最近我正在研究执行关联调度的 c OpenMP 代码。基本上,在线程完成分配的迭代后,它将开始寻找其他具有最多工作负载的线程并从中窃取一些工作。

一切正常,我可以使用 icc 编译文件。但是,当我尝试运行它时,它给了我段错误(核心已转储)。但有趣的是,错误并不总是发生,也就是说,即使我第一次运行代码时出现错误,当我再次尝试运行时,有时它仍然有效。这对我来说太奇怪了。我想知道我的代码做错了什么以及如何解决这个问题。谢谢。我只修改了方法runloop和affinity,其他的都在开头给了,没问题。

#include <stdio.h>
#include <math.h>


#define N 729
#define reps 1000
#include <omp.h>


double a[N][N], b[N][N], c[N];
int jmax[N];


void init1(void);
void init2(void);
void runloop(int);
void loop1chunk(int, int);
void loop2chunk(int, int);
void valid1(void);
void valid2(void);
int affinity(int*, int*, int, int, float, int*, int*);

int main(int argc, char *argv[]) {

double start1,start2,end1,end2;
int r;

init1();

start1 = omp_get_wtime();

for (r=0; r<reps; r++){
runloop(1);
}

end1 = omp_get_wtime();

valid1();

printf("Total time for %d reps of loop 1 = %f\n",reps, (float)(end1-start1));


init2();

start2 = omp_get_wtime();

for (r=0; r<reps; r++){
runloop(2);
}

end2 = omp_get_wtime();

valid2();

printf("Total time for %d reps of loop 2 = %f\n",reps, (float)(end2-start2));

}

void init1(void){
int i,j;

for (i=0; i<N; i++){
for (j=0; j<N; j++){
a[i][j] = 0.0;
b[i][j] = 3.142*(i+j);
}
}

}

void init2(void){
int i,j, expr;

for (i=0; i<N; i++){
expr = i%( 3*(i/30) + 1);
if ( expr == 0) {
jmax[i] = N;
}
else {
jmax[i] = 1;
}
c[i] = 0.0;
}

for (i=0; i<N; i++){
for (j=0; j<N; j++){
b[i][j] = (double) (i*j+1) / (double) (N*N);
}
}

}


void runloop(int loopid)
{
int nthreads = omp_get_max_threads(); // we set it before the parallel region, using opm_get_num_threads() will always return 1 otherwise
int ipt = (int) ceil((double)N/(double)nthreads);
float chunks_fraction = 1.0 / nthreads;
int threads_lo_bound[nthreads];
int threads_hi_bound[nthreads];

#pragma omp parallel default(none) shared(threads_lo_bound, threads_hi_bound, nthreads, loopid, ipt, chunks_fraction)
{
int myid = omp_get_thread_num();
int lo = myid * ipt;
int hi = (myid+1)*ipt;
if (hi > N) hi = N;

threads_lo_bound[myid] = lo;
threads_hi_bound[myid] = hi;

int current_lower_bound = 0;
int current_higher_bound = 0;
int affinity_steal = 0;

while(affinity_steal != -1)
{
switch(loopid)
{
case 1: loop1chunk(current_lower_bound, current_higher_bound); break;
case 2: loop2chunk(current_lower_bound, current_higher_bound); break;
}

#pragma omp critical
{
affinity_steal = affinity(threads_lo_bound, threads_hi_bound, nthreads, myid, chunks_fraction, &current_lower_bound, &current_higher_bound);
}
}
}
}

int affinity(int* threads_lo_bound, int* threads_hi_bound, int num_of_thread, int thread_num, float chunks_fraction, int *current_lower_bound, int *current_higher_bound)
{
int current_pos;

if (threads_hi_bound[thread_num] - threads_lo_bound[thread_num] > 0)
{
current_pos = thread_num;
}
else
{
int new_pos = -1;
int jobs_remain = 0;
int i;
for (i = 0; i < num_of_thread; i++)
{
int diff = threads_hi_bound[i] - threads_lo_bound[i];
if (diff > jobs_remain)
{
new_pos = i;
jobs_remain = diff;
}
}

current_pos = new_pos;
}

if (current_pos == -1) return -1;

int remaining_iterations = threads_hi_bound[current_pos] - threads_lo_bound[current_pos];
int iter_size_fractions = (int)ceil(chunks_fraction * remaining_iterations);

*current_lower_bound = threads_lo_bound[current_pos];
*current_higher_bound = threads_lo_bound[current_pos] + iter_size_fractions;
threads_lo_bound[current_pos] = threads_lo_bound[current_pos] + iter_size_fractions;

return current_pos;
}

void loop1chunk(int lo, int hi) {
int i,j;

for (i=lo; i<hi; i++){
for (j=N-1; j>i; j--){
a[i][j] += cos(b[i][j]);
}
}

}


void loop2chunk(int lo, int hi) {
int i,j,k;
double rN2;

rN2 = 1.0 / (double) (N*N);

for (i=lo; i<hi; i++){
for (j=0; j < jmax[i]; j++){
for (k=0; k<j; k++){
c[i] += (k+1) * log (b[i][j]) * rN2;
}
}
}

}

void valid1(void) {
int i,j;
double suma;

suma= 0.0;
for (i=0; i<N; i++){
for (j=0; j<N; j++){
suma += a[i][j];
}
}
printf("Loop 1 check: Sum of a is %lf\n", suma);

}


void valid2(void) {
int i;
double sumc;

sumc= 0.0;
for (i=0; i<N; i++){
sumc += c[i];
}
printf("Loop 2 check: Sum of c is %f\n", sumc);
}

最佳答案

您没有初始化数组 threads_lo_boundthreads_hi_bound,因此它们最初包含一些完全随机的值(这是随机数 1 的来源)。

然后您进入并行区域,必须意识到并非所有线程都将同步通过代码,每个线程的实际速度是相当随机的,因为它与许多其他程序共享 CPU,即使它们仅使用 1%,它仍然会显示(这是随机数 2 的来源,我认为这与您为什么不时看到它起作用的原因更相关)。

那么当代码崩溃时会发生什么?

其中一个线程(很可能是主线程)在至少一个其他线程到达您设置 threads_lo_bound[myid]threads_hi_bound[myid] 的行之前到达临界区]

在那之后,根据存储在其中的那些随机值是什么(您通常可以假设它们超出范围,您的数组相当小,这些值是有效索引的几率非常小),线程将尝试通过将 current_lower_bound 和/或 current_upper_bound 设置为超出初始数组范围的某个值来窃取一些工作(不存在)a , b, c

然后它将进入 while(affinity_steal != -1) 循环的第二次迭代并访问越界的内存,这不可避免地会导致段错误(最终,原则上它是未定义的行为并且崩溃可能在无效内存访问后的任何时候发生,或者在某些情况下永远不会发生,这会让您相信一切都井井有条,但实际上并非如此。

修复当然很简单,添加

#pragma omp barrier

就在 while(affinity_steal != -1) 循环之前确保所有线程都已到达该点(即在该点同步线程)并且在您继续之前正确设置边界环形。这样做的开销很小,但是如果出于某种原因您希望避免使用障碍,您可以在进入并行区域之前简单地设置数组的值。

也就是说,像这样的错误通常可以使用一个好的调试器来定位,我强烈建议学习如何使用它,它们会让生活变得更加轻松。

关于c - OpenMP 段错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53550999/

48 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com