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