使用OpenMP的C代码出现段错误,请求排查原因
问题排查:OpenMP并行化ip循环导致段错误
问题描述
我正在编写一段用于聚类分析的C语言代码,尝试用OpenMP并行化ip循环,但运行时一直出现段错误。移除ip循环前的#pragma omp parallel for指令后,程序能正常编译运行。我调整过变量的shared和private属性,但问题依旧,希望有人帮忙排查错误原因。
代码片段
#include <stdlib.h> #include <omp.h> #include <time.h> #include "mt19937ar.h" /* Function prototypes for cluster analysis routines */ void find_clusters_recursive(long Nvert,long Maxcon,long *Ncon,long *Lcon,long *lclus, long *nclus); void find_clusters_eqclass (long Nvert,long Maxcon,long *Ncon,long *Lcon,long *lclus, long *nclus); int main () { /* Number of vertices */ const long Nvert = 5000; /* Numnber of graphs to average over at each Pcon */ long Ngraphs = 20; /* Number of Pcon values to test */ long Np = 8; /* Step incrementing probability of connecting any two vertices */ const double Pcon_step = 0.0004; /* Current value of probability of connecting any two vertices */ /* Range is from Pcon_step to Pcon_step*Np */ double Pcon; /* Maximum number of edges per vertex */ const long Maxcon = 80; /* Array holding the number of edges at each vertex */ long *Ncon; /* Array holding a list of connections from each vertex ie if Lcon[i*Maxcon+k] = j then the kth connection from vertex i is to vertex j and we count from the zeroth connection */ long *Lcon; /* Size of largest cluster, and number of clusters */ long lclus,nclus,avlclus,avnclus; /* Initial and final times */ struct timespec ti,tf; double t_start,t_end; /* Random number */ double xi; /* Time taken to generate statistics */ double gentime; /* Loop counters */ long i,j,igraph,ip; /*------------------------------------/ / Initialise random number generator / /------------------------------------*/ unsigned long seed=2483781687; unsigned long myseed; #pragma omp parallel default(shared) private(myseed) { myseed = seed; #ifdef _OPENMP /* Modify seed to be unique on each thread */ myseed = myseed*(omp_get_thread_num()+1); #endif init_genrand(myseed); } /*------------/ / Start timer / /------------*/ #ifndef _OPENMP /* Use clock_gettime */ clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&ti); t_start = (double)ti.tv_sec + ti.tv_nsec/1.0E9; #endif #ifdef _OPENMP /* Use OpenMP clock */ t_start = omp_get_wtime(); #endif /*--------------------------------/ / Loop over values of Pcon / /--------------------------------*/ #pragma omp parallel for default(shared) private(ip,Pcon) //directive for ip for loop for (ip=0;ip<Np;ip++) { /* Compute Pcon from ip */ Pcon = (double)(ip+1)*Pcon_step; /*----------------------/ / Initialise averages / /----------------------*/ avlclus = 0.0; avnclus = 0.0; /*------------------/ / Loop over graphs / /------------------*/ for (igraph=0;igraph<Ngraphs;igraph++) { /*--------------------------------------------/ / Allocate memory to hold graph connectivity / /--------------------------------------------*/ Ncon = (long *)malloc(Nvert*sizeof(long)); if (Ncon==NULL) { printf("Error allocating Ncon array\n") ; exit(EXIT_FAILURE); } Lcon = (long *)malloc(Nvert*Maxcon*sizeof(long)); if (Lcon==NULL) { printf("Error allocating Lcon array\n") ; exit(EXIT_FAILURE); } /*-----------------------------/ / Generate a new random graph / /-----------------------------*/ for (i=0;i<Nvert;i++) { Ncon[i] = 0; } /* Initialise num. connections */ for (i=0;i<Nvert*Maxcon;i++) { Lcon[i] = -1; } /* Initialise connection list */ for (i=0;i<Nvert;i++) { /* Loop over vertices i */ for (j=i+1;j<Nvert;j++) { /* Loop over other vertices j */ xi = genrand(); /* Generate random number xi */ if ( xi < Pcon ) { /* Randomly choose to form an edge */ Ncon[i] = Ncon[i] + 1; /* Increment edges involving i */ Ncon[j] = Ncon[j] + 1; /* Increment edges involving j */ /* Check that we will not overrun the end of the Lcon array */ if ( ( Ncon[i] > Maxcon-1 ) || ( Ncon[j] > Maxcon-1 ) ) { printf("Error generating random graph.\n"); printf("Maximum number of edges per vertex exceeded!\n"); exit(EXIT_FAILURE); } Lcon[Maxcon*i+Ncon[i]-1] = j; /* j is connected to i */ Lcon[Maxcon*j+Ncon[j]-1] = i; /* i is connected to j */ } /* if */ } /* j */ } /* i */ /*-----------------------------------------------------------/ / Identify the clusters through a recusive search over edges / /-----------------------------------------------------------*/ /* find_clusters_recursive(Nvert,Maxcon,Ncon,Lcon,&lclus,&nclus); */ /*----------------------------------------------------------/ / Identify clusters via an equivalence class algorithm / /----------------------------------------------------------*/ find_clusters_eqclass(Nvert,Maxcon,Ncon,Lcon,&lclus,&nclus); /* Accumulate averages */ avlclus += (double)lclus; avnclus += (double)nclus; /*----------------/ / Release memory / /----------------*/ free(Lcon); free(Ncon); printf("Pcon = %12.4f Av. Num. Clusters. = %12.4f Av. Largest Cluster = %12.4f\n", Pcon,avnclus/(double)Ngraphs,avlclus/(double)Ngraphs); } /* end loop over ip */ /*------------------------/ / Check timer / /------------------------*/ #ifndef _OPENMP /* Use clock_gettime */ clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&tf); t_end = (double)tf.tv_sec + tf.tv_nsec/1.0E9; #endif #ifdef _OPENMP /* Use OpenMP clock */ t_end = omp_get_wtime(); #endif gentime = t_end-t_start; printf("Time elapsed : %12.4f seconds\n",gentime); exit(EXIT_SUCCESS); }
错误原因分析及修复方案
- 变量共享冲突:
lclus、nclus、avlclus、avnclus、i、j、igraph、xi这些变量在并行区域默认是shared的,多个线程同时读写会引发数据竞争,导致内存访问错误。- 修复:在
#pragma omp parallel for中显式声明这些变量为private,让每个线程拥有独立副本:#pragma omp parallel for default(shared) private(ip,Pcon,igraph,i,j,xi,lclus,nclus,avlclus,avnclus,Ncon,Lcon)
- 修复:在
- 随机数生成器线程安全问题:
genrand()如果不是线程安全的,多线程同时调用会导致未定义行为。虽然初始化时给每个线程分配了独立种子,但需确保随机数生成器的内部状态是线程私有。- 修复:如果
mt19937ar.h中的生成器未使用线程本地存储,需为每个线程维护独立的随机数状态,比如将状态结构体声明为线程私有变量。
- 修复:如果
- 内存指针复用问题:
Ncon和Lcon未声明为private时,多个线程会复用同一个指针,可能导致重复释放内存或访问野指针。- 修复:将
Ncon和Lcon加入private列表,确保每个线程拥有自己的指针副本。
- 修复:将
修复后的并行指令示例
#pragma omp parallel for default(shared) private(ip,Pcon,igraph,i,j,xi,lclus,nclus,avlclus,avnclus,Ncon,Lcon)
内容的提问来源于stack exchange,提问作者2342
相关产品推荐
相关产品推荐

