MPI用户定义的数据类型,我在做什么安全?

时间:2022-12-06 05:05:24

First time using MPI outside some simple practice apps, and something's not going right.

第一次在一些简单的练习应用之外使用MPI,而且有些事情不对。

I have a class defined with the following members (methods omitted for the sake of readability and conserving screen space):

我有一个使用以下成员定义的类(为了可读性和节省屏幕空间而省略了方法):

class particle
{
    public:
        double _lastUpdate;
    float _x, _y, _xvel, _yvel;
    bool _isStatic;
        bool _isForeign;
        float _size;

    private:
        int _isStaticInt;           // integer copy of _isStatic to be sent over MPI ( since there's no MPI_BOOL :C )
};

I want to send sets of particles between processes by sending the values of some key members of each particle, and replicating the others on the spot. For that purpose, I define an MPI datatype as such; as you can see, members _lastUpdate, _isStatic and _isForeign are not included:

我想通过发送每个粒子的一些关键成员的值,并在现场复制其他粒子来在进程之间发送粒子集。为此,我定义了一个MPI数据类型;如您所见,成员_lastUpdate,_isStatic和_isForeign不包括在内:

MPI_Datatype types[] = { MPI_FLOAT, MPI_FLOAT, MPI_FLOAT, MPI_FLOAT, MPI_INTEGER, MPI_FLOAT };
std::vector<int> len(6, 1);
std::vector<MPI_Aint> disp(6, 0);
particle temp;
MPI_Aint base;
MPI_Address(&temp, &base);
MPI_Address(&temp._x, &disp[0]);
MPI_Address(&temp._y, &disp[1]);
MPI_Address(&temp._xvel, &disp[2]);
MPI_Address(&temp._yvel, &disp[3]);
MPI_Address(&temp._isStaticInt, &disp[4]);
MPI_Address(&temp._size, &disp[5]);
for (int i=0; i<6; ++i)
{
    disp[i] = disp[i] - base;
}
MPI_Type_struct(6, &len[0], &disp[0], types, &_particleType);
MPI_Type_commit(&_particleType);

This is how I send the particles; 'parts' is a vector of particle* that contains pointers to the particle objects I want to send, and 'size' is parts.size().

这是我发送粒子的方式; 'parts'是粒子*的向量,包含指向我想要发送的粒子对象的指针,'size'是parts.size()。

std::vector<int> len(size, 1);
std::vector<MPI_Aint> disp(size, 0);
MPI_Aint base;
MPI_Address(parts[0], &base);                   // datatype begins at the first selected object
for (int select = 1; select < size; ++select)
{
    MPI_Address(parts[select], &disp[select]);
    disp[select] = disp[select] - base;
}
MPI_Type_hindexed(size, &len[0], &disp[0], _particleType, &_sendType);
MPI_Type_commit(&_sendType);

MPI_Request payload_req;
MPI_Isend(parts[0], 1, _sendType, ngb, 0, _cartesian_comm, &payload_req);

Receiving happens similarly, only in this case, 'parts' is a vector of particle* that points to previously created "blank" particle objects, whose members are to be filled with the data we receive:

接收发生的情况类似,只有在这种情况下,'parts'是一个粒子*的向量,它指向先前创建的“空白”粒子对象,其成员将填充我们收到的数据:

std::vector<int> len(size, 1);
std::vector<MPI_Aint> disp(size, 0);
MPI_Aint base;
MPI_Address(parts[0], &base);                       // datatype begins at the first newly inserted object
for (int part = 1; part < size; ++part)
{
    MPI_Address(parts[part], &disp[part]);
    disp[part] = disp[part] - base;
}
MPI_Type_hindexed(size, &len[0], &disp[0], _particleType, &_recvType);
MPI_Type_commit(&_recvType);
MPI_Status status;
MPI_Recv(parts[0], size, _particleType, ngb, 0, _cartesian_comm, &status);

The problem is that all the received particles except the first one have the default "blank" values in their members. I wrote a small test app before that did something similar, and that worked flawlessly, although it only transmitted a few simple values. This leads me to beleive that unless there's a coding mistake I'm not noticing here (entirely possible), this sort of datatype trickery is not guaranteed to work, and the little that works does so only by accident.

问题是除了第一个之外的所有接收粒子在其成员中都具有默认的“空白”值。我之前写了一个小测试应用程序做了类似的事情,尽管只传递了一些简单的值,但它完美无瑕。这让我相信,除非我在这里没有注意到编码错误(完全可能),否则这种数据类型的技巧并不能保证能够正常工作,并且只有偶然才会有效。

Can anyone confirm/deny if this type of memory manipulation is safe and should be relied upon?

任何人都可以确认/否认这种类型的内存操作是否安全并且应该依赖它?

1 个解决方案

#1


Never mind, it seems that simply typing out the question made me realize what's wrong.

没关系,似乎只是输入问题让我意识到什么是错的。

The receive command should be:

receive命令应该是:

MPI_Recv(parts[0], 1, _recvType, ngb, 0, _cartesian_comm, &status);

#1


Never mind, it seems that simply typing out the question made me realize what's wrong.

没关系,似乎只是输入问题让我意识到什么是错的。

The receive command should be:

receive命令应该是:

MPI_Recv(parts[0], 1, _recvType, ngb, 0, _cartesian_comm, &status);