【问题标题】:Pointer value assignment in C and MPI environmentC 和 MPI 环境中的指针赋值
【发布时间】:2019-01-17 10:19:36
【问题描述】:

我有一个使用 MPI 的 C 代码 sn-p 如下:

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

int main(int argc, char *argv[])
{
float **p=NULL, **buffer=NULL;
int it, nt=3, i, j, k, NP, MYID, nx=1, nz=2, nsrc=3, isrc;

MPI_Init ( &argc, &argv );
MPI_Comm_size ( MPI_COMM_WORLD, &NP );
MPI_Comm_rank ( MPI_COMM_WORLD, &MYID ); 

p = (float **)calloc(nz,sizeof(float *));
for (i=0;i<nz;i++) p[i] = (float *)calloc(nx,sizeof(float));
buffer = (float **)calloc(nz,sizeof(float *));
for (i=0;i<nz;i++) buffer[i] = (float *)calloc(nx,sizeof(float));

for (it=0; it<nt; it++){        
    for (isrc=MYID; isrc<nsrc; isrc+=NP){
        for (j=0; j<nz; j++){
            for (i=0; i<nx; i++){
                p[j][i] += 1.5 + (float)(isrc) + (float)(j);
            }
        }            
    }

    for (k=0;k<nsrc-1;k++){ 
        if (MYID==k){ 
            buffer = p;  /*swap pointer*/          
        }
        MPI_Barrier(MPI_COMM_WORLD);
        MPI_Bcast(&buffer[0][0],nx*nz,MPI_FLOAT,k,MPI_COMM_WORLD);
        MPI_Barrier(MPI_COMM_WORLD);
        for (j=0; j<nz; j++){
            for (i=0; i<nx; i++){
                printf("it=%d,k=%d,Node %d,buffer[%d][%d]=%f\n",it,k,MYID,j,i,buffer[j][i]);
            }
        }            
    }     
}

MPI_Finalize();
exit(0);
}

如果你用 3 核 mpirun -np 3 ./main 运行它,它会给出错误的结果:

it=0,k=0,Node 0,buffer[0][0]=1.500000
it=0,k=0,Node 0,buffer[1][0]=2.500000
it=0,k=1,Node 0,buffer[0][0]=2.500000
it=0,k=1,Node 0,buffer[1][0]=3.500000
it=0,k=0,Node 1,buffer[0][0]=1.500000
it=0,k=0,Node 1,buffer[1][0]=2.500000
it=0,k=1,Node 1,buffer[0][0]=2.500000
it=0,k=1,Node 1,buffer[1][0]=3.500000
it=1,k=0,Node 1,buffer[0][0]=4.000000
it=1,k=0,Node 1,buffer[1][0]=6.000000
it=0,k=0,Node 2,buffer[0][0]=1.500000
it=0,k=0,Node 2,buffer[1][0]=2.500000
it=0,k=1,Node 2,buffer[0][0]=2.500000
it=0,k=1,Node 2,buffer[1][0]=3.500000
it=1,k=0,Node 2,buffer[0][0]=4.000000
it=1,k=0,Node 2,buffer[1][0]=6.000000
it=1,k=1,Node 2,buffer[0][0]=4.000000
it=1,k=0,Node 0,buffer[0][0]=4.000000
it=1,k=0,Node 0,buffer[1][0]=6.000000
it=1,k=1,Node 0,buffer[0][0]=4.000000
it=1,k=1,Node 0,buffer[1][0]=6.000000
it=1,k=1,Node 1,buffer[0][0]=4.000000
it=1,k=1,Node 1,buffer[1][0]=6.000000
it=2,k=0,Node 1,buffer[0][0]=5.500000
it=1,k=1,Node 2,buffer[1][0]=6.000000
it=2,k=0,Node 2,buffer[0][0]=5.500000
it=2,k=0,Node 2,buffer[1][0]=8.500000
it=2,k=0,Node 0,buffer[0][0]=5.500000
it=2,k=0,Node 0,buffer[1][0]=8.500000
it=2,k=0,Node 1,buffer[1][0]=8.500000
it=2,k=1,Node 1,buffer[0][0]=5.500000
it=2,k=1,Node 0,buffer[0][0]=5.500000
it=2,k=1,Node 0,buffer[1][0]=8.500000
it=2,k=1,Node 1,buffer[1][0]=8.500000
it=2,k=1,Node 2,buffer[0][0]=5.500000
it=2,k=1,Node 2,buffer[1][0]=8.500000

但是,如果我将/*swap pointer*/ 的行更改为以下内容:

for (j=0; j<nz; j++){
     for (i=0; i<nx; i++){
          buffer[j][i] = p[j][i];  
     }
}  

代码立即给出正确的结果:

it=0,k=0,Node 0,buffer[0][0]=1.500000
it=0,k=0,Node 0,buffer[1][0]=2.500000
it=0,k=0,Node 1,buffer[0][0]=1.500000
it=0,k=0,Node 1,buffer[1][0]=2.500000
it=0,k=0,Node 2,buffer[0][0]=1.500000
it=0,k=0,Node 2,buffer[1][0]=2.500000
it=0,k=1,Node 0,buffer[0][0]=2.500000
it=0,k=1,Node 0,buffer[1][0]=3.500000
it=0,k=1,Node 1,buffer[0][0]=2.500000
it=0,k=1,Node 1,buffer[1][0]=3.500000
it=0,k=1,Node 2,buffer[0][0]=2.500000
it=0,k=1,Node 2,buffer[1][0]=3.500000
it=1,k=0,Node 2,buffer[0][0]=3.000000
it=1,k=0,Node 0,buffer[0][0]=3.000000
it=1,k=0,Node 0,buffer[1][0]=5.000000
it=1,k=0,Node 1,buffer[0][0]=3.000000
it=1,k=0,Node 1,buffer[1][0]=5.000000
it=1,k=0,Node 2,buffer[1][0]=5.000000
it=1,k=1,Node 2,buffer[0][0]=5.000000
it=1,k=1,Node 0,buffer[0][0]=5.000000
it=1,k=1,Node 0,buffer[1][0]=7.000000
it=1,k=1,Node 1,buffer[0][0]=5.000000
it=1,k=1,Node 1,buffer[1][0]=7.000000
it=1,k=1,Node 2,buffer[1][0]=7.000000
it=2,k=0,Node 2,buffer[0][0]=4.500000
it=2,k=0,Node 2,buffer[1][0]=7.500000
it=2,k=0,Node 0,buffer[0][0]=4.500000
it=2,k=0,Node 0,buffer[1][0]=7.500000
it=2,k=0,Node 1,buffer[0][0]=4.500000
it=2,k=0,Node 1,buffer[1][0]=7.500000
it=2,k=1,Node 0,buffer[0][0]=7.500000
it=2,k=1,Node 1,buffer[0][0]=7.500000
it=2,k=1,Node 2,buffer[0][0]=7.500000
it=2,k=1,Node 2,buffer[1][0]=10.500000
it=2,k=1,Node 0,buffer[1][0]=10.500000
it=2,k=1,Node 1,buffer[1][0]=10.500000

我的问题是:为什么我只是改变分配值的方式会改变输出的正确性?

【问题讨论】:

  • 如果您要立即初始化所有数组元素,则无需使用calloc()。它会将它们全部初始化为零,这是不必要的,因为您要替换它们。
  • for (i&lt;0;i&lt;nz;i++) 对吗?循环以i 0 或 1 开头。
  • @WeatherVane 为什么没有意义?我一开始使用buffer = p,但输出错误;但是当使用 for 循环一一分配值时会给出正确的答案。你不认为我们必须明白为什么吗?这就是为什么我在这里请求您的帮助。
  • 因为i 尚未初始化。所以比较它是未定义的行为。

标签: c arrays pointers parallel-processing mpi


【解决方案1】:

我认为你的问题归结为,为什么是

buffer = p;

不同于

for (j=0; j<nz; j++){
     for (i=0; i<nx; i++){
          buffer[j][i] = p[j][i];  
     }
}   

buffer = p 是浅拷贝,而 for 循环是深拷贝。在浅拷贝中,我们正在更改缓冲区存储所有元素的位置。在深拷贝中,我们保留 buffer 存储它的所有元素的位置,然后将 p 的所有元素复制到这里。

这种行为出乎意料的原因是因为在浅拷贝情况下,缓冲区和 p 存储它们的所有元素重叠,因此广播和分配写入相同的内存。

【讨论】:

  • 但是在第二个it循环中,p的值也发生了变化,为什么buffer仍然保持原来的值?
【解决方案2】:

首先,您需要在连续内存中分配 (2D) 数组。

否则您只广播第一行并导致缓冲区溢出,从而导致未定义的行为。

请注意,您已经发布了一堆问题,而根本原因总是相同的:您需要在连续的内存中分配您的数组(并且有大量关于 SO 的示例)。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2011-10-27
    • 2018-04-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-05-15
    • 1970-01-01
    相关资源
    最近更新 更多