第一次在一些简单的练习应用程序之外使用 MPI,但出现了一些问题。
我有一个用以下成员定义的类(为了可读性和节省屏幕空间而省略了方法):
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 )
};
我想通过发送每个粒子的一些关键成员的值并在现场复制其他粒子来在进程之间发送粒子集。为此,我定义了一个 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);
这就是我发送粒子的方式;“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);
接收类似地发生,只是在这种情况下,“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);
问题是除了第一个粒子之外,所有接收到的粒子在其成员中都有默认的“空白”值。在此之前我写了一个小型测试应用程序,做了类似的事情,并且运行良好,尽管它只传输了一些简单的值。这让我相信,除非有我在这里没有注意到的编码错误(完全有可能),否则这种数据类型的诡计并不能保证有效,而且这种做法只是偶然发生的。
任何人都可以确认/否认这种类型的内存操作是否安全并且应该依赖?