You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 08:01:34