The C language OpenMP memory issues when creating and destroying array of structures

75 Views Asked by At

In the serial part of my C code I am allocating (dynamically) the array of arrays of my structures CONF:

CONF **conf = (CONF **) malloc (Nc*sizeof(CONF *)); 

Nc is a variable that is obtained when the code is running. Each array conf[i] has its own size, that is stored separately in the long int array Nc_size. Then I am allocating each conf[i]:

for (i=0; i<Nc; i++) {
    long int sz;
    // all but last                                         
    if (i+1!=Nc) {
        sz = MC;
    }
    // last                                                 
    else {
        sz = conflistd%MC;
    }
    Nc_size[i] = sz;
    (conf)[i] = (CONF *) malloc(sz*sizeof(CONF));

CONF is a complex structure that contains among the other things dynamic double arrays. In the next step I am filling up all conf[i].

Then, I would like to modify each conf[i] with a function CLUSTERINGL, and I really want to do it in a parallel mode via OpenMP:

#pragma omp parallel private(i, NIR) shared(conf, Nc_size)
{
    #pragma omp for
    for (i=0; i<Nc; i++) {
        conf[i] = CLUSTERINGL (conf[i], &sz, ...);
    }
}

In the function CLUSTERINGL, a new, smaller-size array of structures CONF is first created, and then populated with a subset of conf[i], and then returned. Meanwhile the original conf[i] (and its contents) is destroyed with free.

CONF *CLUSTERINGL(CONF *conflist1, long int *conflist1d, ...) {

    CONF *conflist3 = malloc(1 * sizeof(CONF));

    for (j = 0; j < k; j++) {
        if (arrayofconf[j][0] > -1) {
            long int NFR = conflist1[j].NFR;
            i = arrayofconf[j][0];
            // if the is closest to the centeroid
            conflist3 =
                (CONF *)realloc(conflist3, (conflist3d + 1) * sizeof(CONF));
            conflist3[conflist3d].IR = malloc(NIR * sizeof(double));
            conflist3[conflist3d].angles = malloc(NBONDS * sizeof(double));
            conflist3[conflist3d].TR = malloc(3 * (NFR + 1) * sizeof(double));
            conflist3[conflist3d].ROT = malloc(3 * (NFR + 1) * sizeof(double));

            conflist3d++;
        }
    }

    // ...
    // ...
    // ...

    for (i = 0; i < *conflist1d; i++) {
        if (NIR != 0) {
            free(conflist1[i].IR);
        }
        free(conflist1[i].angles);
        free(conflist1[i].TR);
        free(conflist1[i].ROT);
    }

    free(conflist1);

    *conflist1d = conflist3d;
    return conflist3;
}

When this code run in serial, everything is OK. However, in the parallel mode I am having segfault almost every run.

I would be grateful for any comments or suggestions. My wild guess is that to the function CLUSTERINGL conf[i] should also be passed with the & symbol.

A small update: I tried to reproduce the error with a smaller code, but it turns out to work stable. But just to be sure that everything is conceptually right and I learned something, could you please confirm that this smaller code is correct. It is compiled as gcc main.c -fopenmp -lm

maintypes.h:

#include <inttypes.h>

typedef struct {
  long int N;
  double *IR;
} CONF;

main.c:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <stdbool.h>
#include "maintypes.h"
#include <string.h>
#include <ctype.h>
#include <omp.h>
#include <time.h>

CONF *CLUSTERINGL (CONF *conf1, long int *conf1d, long int NIR);


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

// check that the file argument was given
if (argc < 2) {
        printf ("%s","Please, give the number NA\n");
        exit(0);
}

long int conflistd = atoi(argv[1]);
long int MC = 100;
long int NIR = 30;
long int Nc = conflistd/MC + 1;
long int Nc_size[Nc];
//

CONF **conf = (CONF **) malloc (Nc*sizeof(CONF *));

// loop variables

long int i=0, j=0;
long int count=0;

for (i=0; i<Nc; i++) {
  long int sz;
  // all but last
  if (i+1!=Nc) {
    sz = MC;
  }
  // last
  else {
    sz = conflistd%MC;
  }
  Nc_size[i] = sz;                      
  (conf)[i] = (CONF *) malloc(sz*sizeof(CONF));
  for (j=0;j<sz;j++) {
    conf[i][j].N = count;
    conf[i][j].IR = malloc(NIR*sizeof(double));
    for (long int m=0;m<NIR;m++) {
      conf[i][j].IR[m] = 1.33*m;
    }
    count = count + 1;   
  }

}

printf ("Starting parallel\n");
#pragma omp parallel private(i) shared (conf, Nc_size, Nc, NIR) default(none)
{
#pragma omp for
for (i=0;i<Nc;i++) {
  long int sz = Nc_size[i];
  if (sz>4) {
    conf[i] = CLUSTERINGL(conf[i], &sz, NIR);
    Nc_size[i] = sz;
  }
}

}

return 0;
}


CONF *CLUSTERINGL (CONF *conf1, long int *conf1d, long int NIR) {

long int d = *conf1d/3;
CONF *confnew = (CONF *) malloc (d*sizeof(CONF));

long int j=0;

for (j=0;j<d;j++) {
  confnew[j].N = conf1[j].N;
  confnew[j].IR = malloc(NIR*sizeof(double));
  for (long int m=0;m<NIR;m++) {
    confnew[j].IR[m] = pow(sqrt(conf1[j].IR[m])*5*j,1.8);
    confnew[j].IR[m]*5;
    confnew[j].IR[m]*confnew[j].IR[m];
  }
}


// cleaning

for (j=0;j<*conf1d;j++) {
  free (conf1[j].IR);
}

free (conf1);

*conf1d=d;

return confnew;
}

execute: ./a.out 10000000

0

There are 0 best solutions below