MPI_Bcast dynamic array 2d

I am trying to pass a 2d dynamic array with bcast for all ranks. I have the following code.

#include <stdlib.h> #include <mpi.h> int main(int argc, char **argv) { float **array; int rank,size,i,j; MPI_Init(&argc,&argv); MPI_Comm_rank(MPI_COMM_WORLD,&rank); MPI_Comm_size(MPI_COMM_WORLD,&size); if(rank==0) { array = (float **)malloc(10*sizeof(float)); for(i=0;i<10;i++) array[i] = (float *)malloc(10*sizeof(float)); for(i=0;i<10;i++) for(j=0;j<10;j++) array[i][j]=i+j; } MPI_Bcast(array,10*10,MPI_FLOAT,0,MPI_COMM_WORLD); MPI_Finalize(); } 

For some reason, I cannot understand that I received a segmentation error. Who knows what the problem is?

+8
c mpi
source share
5 answers

array should be 100, not 10, since you assign 10 floats for each row. Answer JackN has code for this.

However, in any process other than rank 0, the pointer to the array will be null . You need to initialize the array for all processes, and then fill the array in the root.

You can simply move the malloc code from the if (rank ==0) block if (rank ==0) , and it should work as you expect.

+6
source share

There are three problems: one is with distribution, one of which is related to distribution, and the other is using MPI, and none of the other answers affects them all.

The first and most serious problem is where things are distributed. As @davidb correctly pointed out, as it stands, you only allocate memory for task zero, so other tasks do not have memory to receive the broadcast.

As with 2d distributions in C, your code is almost exactly right. In this block of code:

  array = (float **)malloc(10*sizeof(float)); for(i=0;i<10;i++) array[i] = (float *)malloc(10*sizeof(float)); 

the only real problem is that the first malloc should have 10 floating pointers, not a float:

  array = (float **)malloc(10*sizeof(float *)); for(i=0;i<10;i++) array[i] = (float *)malloc(10*sizeof(float)); 

This was pointed out by @eznme. The first method may work depending on which memory model you are compiling / linking, etc., and will almost certainly work on 32-bit OS / machines, but just because it works, this does not always mean :)

Now, the last problem is that you declared an excellent 2d array in C, but that is not what MPI expects. When you make this call

 MPI_Bcast(array,10*10,MPI_FLOAT,0,MPI_COMM_WORLD); 

you tell MPI to send 100 contiguous floats pointed to by array . You noticed that the library routine has no way of knowing if the array is a pointer to the beginning of a 2d or 3d or 12d array or what the individual dimensions are; he does not know if he should follow the signs, and if this happened, he would not know how many of them follow.

So, you want to send a floating-point pointer to 100 adjacent floats - and in the usual way of allocating pseudo-multidimensional arrays (*), this is not necessary for you. You do not necessarily know how far the 2nd row is from the 1st row in this layout - or even in which direction. So what you really want to do is something like this:

 int malloc2dfloat(float ***array, int n, int m) { /* allocate the n*m contiguous items */ float *p = (float *)malloc(n*m*sizeof(float)); if (!p) return -1; /* allocate the row pointers into the memory */ (*array) = (float **)malloc(n*sizeof(float*)); if (!(*array)) { free(p); return -1; } /* set up the pointers into the contiguous memory */ for (int i=0; i<n; i++) (*array)[i] = &(p[i*m]); return 0; } int free2dfloat(float ***array) { /* free the memory - the first element of the array is at the start */ free(&((*array)[0][0])); /* free the pointers into the memory */ free(*array); return 0; } 

Thus, and only in this way you guarantee that the memory will be continuous. Then you can do

 float **array; /* ... */ malloc2dfloat(&array, 10, 10); if (rank == 0) { for(i=0;i<10;i++) for(j=0;j<10;j++) array[i][j]=i+j; } MPI_Bcast(&(array[0][0]), 10*10, MPI_FLOAT, 0, MPI_COMM_WORLD); 

Note that for arbitrary data composition, you can still make a Bcast by specifying an MPI data type that describes how the 2d array is actually laid out in memory; but it’s easier and closer to what you really want.

(*) the real problem is that the C and C languages ​​do not have real multi-d arrays as first-class objects, which is great for a system programming language, but it is naturally not annoying when programming.

+22
source share

The array must be 100, not 10.

 array = (float **)malloc(100*sizeof(float)); 
+2
source share

You probably want to change the first malloc to

 malloc(10*sizeof(void*)) 

because the array stores pointers and stores float instead of ints:

 array[i][j]=1.0; 
+1
source share

if you want to allocate an array with 10 * 10, your code:

 array = (float **)malloc(10*sizeof(float)) 

it should be

 array = (float **)malloc(10*sizeof(float*)) 
0
source share

All Articles