在MPI中发送和接收动态数组

时间:2014-07-25 07:50:54

标签: c arrays mpi dynamic-arrays

发送和(或)接收带MPI的动态数组时遇到了很大问题。下面只是我的代码的一部分,但它应该足以看到我做错了什么。请帮帮我,我整晚都在搜索解决方案。 我是这样的: 检测到 * glibc ./mv2.out:munmap_chunk():无效指针:0x0000000000da2a70 glibc ./mv2.out:malloc():内存损坏(快速):0x0000000000da2a50 *

当我用静态替换动态数组时,一切都很完美。

#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>

#define MASTER 0
#define FROM_MASTER 1
#define FROM_WORKER 2

double **alloc_2d_array(int rows, int cols) {
    int i;
    double *data = (double *)malloc(rows*cols*sizeof(double));
    double **array= (double **)malloc(rows*sizeof(double*));
    for (i=0; i<rows; i++)
        array[i] = &(data[cols*i]);

    return array;
}

int main (int argc, char *argv[])
{
    int degree,
    numtasks,
    taskid,
    numworkers,
    source,
    dest,
    mtype,
    rows,
    offset,
    averow,
    extra,
    i, j, k, rc;

    MPI_Status status;

    double **a, *b, *c;

    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&taskid);
    MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
    if (numtasks < 2 )
    {
        printf("Aby rozpoczac obliczenia rownolegle potrzeba co najmniej 2 procesow.\n");
        MPI_Abort(MPI_COMM_WORLD, rc);
        exit(1);
    }
    numworkers = numtasks-1; 

    if (taskid == MASTER)
    {
        printf("Podaj stopien macierzy: \n");
        scanf ("%d", &degree);
        printf("Obecnie dostepnych jest %d procesow do dyspozycji mastera.\n", numtasks);

        FILE *file;

        file = fopen("matrix.txt", "r");
        if(file == NULL)
        {
            printf("Nie mozna otworzyc pliku!\n");
            MPI_Finalize();
            exit(0);
        }

        a = alloc_2d_array(degree, degree);
        b = (double*) malloc(sizeof(double) * degree);
        c = (double*) malloc(sizeof(double) * degree);

        printf("Tworzenie macierzy z pliku\n");
        for(i = 0; i < degree; i++)
            for(j = 0; j < degree; j++)
                fscanf(file, "%lf", &a[i][j]);

        for(i = 0; i < degree; i++)
        {
            for(j = 0; j < degree; j++)
            {
                printf("%f", a[i][j]);
            }
            printf("\n");
        }

        printf("Tworzenie wektora z pliku\n");
        for(i = 0; i < degree; i++)
            fscanf(file, "%lf", &b[i]);

        for(i = 0; i < degree; i++)
        {
            printf("%f\n", b[i]);
        }

        fclose(file);

        averow = degree / numworkers;
        extra = degree % numworkers;
        offset = 0;
        mtype = FROM_MASTER;
        for (dest = 1; dest <= numworkers; dest++)
        {
            rows = (dest <= extra) ? (averow + 1) : averow;
            printf("Wysylanie %d wierszy do procesu nr %d, z offset'em = %d\n", rows, dest, offset);
            MPI_Send(&degree, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
            MPI_Send(&offset, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
            MPI_Send(&rows, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
            MPI_Send(&a[offset][0], rows * degree, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
            MPI_Send(&b, degree, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
            offset = offset + rows;
        }

        mtype = FROM_WORKER;
        for (i=1; i<=numworkers; i++)
        {
            source = i;
            MPI_Recv(&offset, 1, MPI_INT, source, mtype, MPI_COMM_WORLD, &status);
            MPI_Recv(&rows, 1, MPI_INT, source, mtype, MPI_COMM_WORLD, &status);
            MPI_Recv(&c[offset], rows, MPI_DOUBLE, source, mtype, MPI_COMM_WORLD, &status);
            printf("Otrzymalem wyniki od procesu nr %d\n", source);
        }

        printf("***\n");
        printf("Wektor wynikowy:\n");
        for (i = 0; i < degree; i++)
        {
            printf("\n%6.2f", c[i]);
        }
        printf("\n***\n");
        printf ("KONIEC\n");
    }


    if (taskid > MASTER)
    {
        b = (double*) malloc(sizeof(double) * degree);
        c = (double*) malloc(sizeof(double) * degree);

        mtype = FROM_MASTER;
        MPI_Recv(&degree, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&offset, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&rows, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&a, rows * degree, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status); //HERE IS THE PROBLEM
        MPI_Recv(&b, degree, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status);

        for (i = 0; i < rows; i++)
        {
            c[i] = 0.0;
            for (j = 0; j < degree; j++)
                c[i] += a[i][j] * b[j];
        }
        mtype = FROM_WORKER;
        MPI_Send(&offset, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD);
        MPI_Send(&rows, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD);
        MPI_Send(&c, rows, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD);
    }

    MPI_Finalize();
}

重现错误的最短版本:

#include "mpi.h"
#include <stdio.h>
#include <stdlib.h>

#define MASTER 0
#define FROM_MASTER 1
#define FROM_WORKER 2

double **alloc_2d_array(int rows, int cols) {
    int i;
    double *data = (double *)malloc(rows*cols*sizeof(double));
    double **array= (double **)malloc(rows*sizeof(double*));
    for (i=0; i<rows; i++)
        array[i] = &(data[cols*i]);

    return array;
}

int main (int argc, char *argv[])
{
    int degree,
    taskid,
    source,
    dest,
    mtype,
    rows,
    offset,
    i, j;

    MPI_Status status;

    double **a, *b, *c;

    MPI_Init(&argc,&argv);
    MPI_Comm_rank(MPI_COMM_WORLD,&taskid);
    MPI_Comm_size(MPI_COMM_WORLD,&numtasks);

    if (taskid == MASTER)
    {
        FILE *file;

        file = fopen("matrix.txt", "r");

        a = alloc_2d_array(degree, degree);
        b = (double*) malloc(sizeof(double) * degree);
        c = (double*) malloc(sizeof(double) * degree);

        for(i = 0; i < degree; i++)
            for(j = 0; j < degree; j++)
                fscanf(file, "%lf", &a[i][j]);      

        for(i = 0; i < degree; i++)
            fscanf(file, "%lf", &b[i]);

        fclose(file);

        offset = 0;
        mtype = FROM_MASTER;
        MPI_Send(&degree, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
        MPI_Send(&offset, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
        MPI_Send(&rows, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
        MPI_Send(&a[offset][0], rows * degree, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
        MPI_Send(&b, degree, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
        }
    }


    if (taskid > MASTER)
    {
        a = alloc_2d_array(degree, degree);
        b = (double*) malloc(sizeof(double) * degree);
        c = (double*) malloc(sizeof(double) * degree);

        mtype = FROM_MASTER;
        MPI_Recv(&degree, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&offset, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&rows, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
        // v HERE IS THE PROBLEM v
        MPI_Recv(&a, rows * degree, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status);
        MPI_Recv(&b, degree, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status);
    }

    MPI_Finalize();
}

编辑:没有从工作人员发送到主人的版本正常工作,但是当我添加响应应用程序暂停时。 在下面的链接中,您可以找到静态数组的示例。当我用动态替换它们时,应用程序无法正常工作。 https://computing.llnl.gov/tutorials/mpi/samples/C/mpi_mm.c

2 个答案:

答案 0 :(得分:2)

因为你还没有发布一个可以运行和测试的完整程序,所以在这里必须要有点心理(请在将来执行此操作,例如,此处你没有包含所有#includes和#defines,以及你也不提供输入文件)。但是从我可以看到你在recv中的问题是双重的。首先,您没有为“工作”进程分配任何内存。其次,您指定为a的recv的起始地址是不正确的。这是你的代码的缩减版本,它做了我认为你想要的(但我再次猜测)。还请注意C是我的第二语言,所以请检查我做了什么。无论如何它是:

ian@ian-pc:~/test$ cat mpi.c

#include <stdio.h>
#include <stdlib.h>

#include "mpi.h"

#define FROM_MASTER 1
#define FROM_WORKER 2

#define MASTER 0

double **alloc_2d_array(int rows, int cols) {
  int i;
  double *data = (double *)malloc(rows*cols*sizeof(double));
  double **array= (double **)malloc(rows*sizeof(double*));
  for (i=0; i<rows; i++)
    array[i] = &(data[cols*i]);

  return array;
}

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

  int degree, numtasks, taskid, numworkers, dest, mtype, rows, offset, averow, extra, i, j;

  MPI_Status status;

  double **a;

  MPI_Init(&argc,&argv);
  MPI_Comm_rank(MPI_COMM_WORLD,&taskid);
  MPI_Comm_size(MPI_COMM_WORLD,&numtasks);
  if (numtasks < 2 )
    {
      printf("Aby rozpoczac obliczenia rownolegle potrzeba co najmniej 2 procesow.\n");
      MPI_Abort(MPI_COMM_WORLD, EXIT_FAILURE);
      exit(1);
    }
  numworkers = numtasks-1; 

  if (taskid == MASTER)
    {
      printf("Podaj stopien macierzy: \n");
      scanf ("%d", &degree);
      printf("Obecnie dostepnych jest %d procesow do dyspozycji mastera.\n", numtasks);

      a = alloc_2d_array(degree, degree);

      printf("Tworzenie macierzy z pliku\n");
      for(i = 0; i < degree; i++)
    for(j = 0; j < degree; j++)
      a[ i ][ j ] = i + 10 * j;

      printf( "Initial\n" );
      for(i = 0; i < degree; i++) {
    for(j = 0; j < degree; j++) 
      printf("%f ", a[i][j]);
    printf("\n");
      }

      averow = degree / numworkers;
      extra = degree % numworkers;
      offset = 0;
      mtype = FROM_MASTER;
      for (dest = 1; dest <= numworkers; dest++)
        {
      rows = (dest <= extra) ? (averow + 1) : averow;
      MPI_Send(&degree, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
      MPI_Send(&rows, 1, MPI_INT, dest, mtype, MPI_COMM_WORLD);
      MPI_Send(&(a[offset][0]), rows * degree, MPI_DOUBLE, dest, mtype, MPI_COMM_WORLD);
      offset = offset + rows;
        }

    }


  /* Attempt to order output, not gauranteed to work */
  MPI_Barrier( MPI_COMM_WORLD );

  if (taskid > MASTER)
    {

      mtype = FROM_MASTER;
      MPI_Recv(&degree, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
      MPI_Recv(&rows, 1, MPI_INT, MASTER, mtype, MPI_COMM_WORLD, &status);
      a = alloc_2d_array( rows, degree);
      /* MPI_Recv(&a, rows * degree, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status);  */
      MPI_Recv(&(a[0][0]), rows * degree, MPI_DOUBLE, MASTER, mtype, MPI_COMM_WORLD, &status); 

      printf( "Final from %d\n", taskid );
      for(i = 0; i < rows; i++) {
    printf( "%d ", taskid );
    for(j = 0; j < degree; j++)
      printf("%f ", a[i][j]);
    printf("\n");
      }
    }

  MPI_Finalize();

  return EXIT_SUCCESS;

}
ian@ian-pc:~/test$ mpicc -std=c89 -Wall -Wextra -pedantic -O mpi.c
In file included from mpi.c:5:0:
/usr/lib/openmpi/include/mpi.h:220:9: warning: ISO C90 does not support ‘long long’ [-Wlong-long]
mpi.c: In function ‘main’:
mpi.c:45:13: warning: ignoring return value of ‘scanf’, declared with attribute warn_unused_result [-Wunused-result]
ian@ian-pc:~/test$ mpirun -np 3 ./a.out
Podaj stopien macierzy: 
2
Obecnie dostepnych jest 3 procesow do dyspozycji mastera.
Tworzenie macierzy z pliku
Initial
0.000000 10.000000 
1.000000 11.000000 
Final from 1
1 0.000000 10.000000 
Final from 2
2 1.000000 11.000000 
ian@ian-pc:~/test$ mpirun -np 3 ./a.out
Podaj stopien macierzy: 
4
Final from 1
1 0.000000 10.000000 20.000000 30.000000 
1 1.000000 11.000000 21.000000 31.000000 
Final from 2
2 2.000000 12.000000 22.000000 32.000000 
2 3.000000 13.000000 23.000000 33.000000 
Obecnie dostepnych jest 3 procesow do dyspozycji mastera.
Tworzenie macierzy z pliku
Initial
0.000000 10.000000 20.000000 30.000000 
1.000000 11.000000 21.000000 31.000000 
2.000000 12.000000 22.000000 32.000000 
3.000000 13.000000 23.000000 33.000000 
ian@ian-pc:~/test$ mpirun -np 3 ./a.out
Podaj stopien macierzy: 
5
Final from 2
2 3.000000 13.000000 23.000000 33.000000 43.000000 
2 4.000000 14.000000 24.000000 34.000000 44.000000 
Obecnie dostepnych jest 3 procesow do dyspozycji mastera.
Tworzenie macierzy z pliku
Initial
0.000000 10.000000 20.000000 30.000000 40.000000 
1.000000 11.000000 21.000000 31.000000 41.000000 
2.000000 12.000000 22.000000 32.000000 42.000000 
3.000000 13.000000 23.000000 33.000000 43.000000 
4.000000 14.000000 24.000000 34.000000 44.000000 
Final from 1
1 0.000000 10.000000 20.000000 30.000000 40.000000 
1 1.000000 11.000000 21.000000 31.000000 41.000000 
1 2.000000 12.000000 22.000000 32.000000 42.000000 
ian@ian-pc:~/test$ 

但是也要了解MPI_Bcast,它在这里很有用......

答案 1 :(得分:0)

动态分配数组的方式似乎很奇怪。通常你这样做:

double **alloc_2d_array(int rows, int cols) {
    int i;
    double **array= (double **)malloc(rows*sizeof(double*));
    for (i=0; i<rows; i++)
        array[i] = (double *)malloc(rows*cols*sizeof(double));
    return array;
}

然后解除分配也会分两步进行:

void free_2d_array(double*** arrayPtr){
  double **array = *arrayPtr;
  for (i=0; i<rows; i++) free(array[i]);
  free(array);
} 

更新:假设按照最初建议的方式更有效率,分配应该是这样的:

double **alloc_2d_array(int rows, int cols) {
    int i;
    double *data = (double *)malloc(rows*cols*sizeof(double));
    double **array= (double **)malloc(rows*sizeof(double*));
    for (i=0; i<rows; i++)
        array[i] = data + cols*i;

    return array;
}

在这种情况下,释放也很容易:为两个数组调用free