[mpich-discuss] Problems with MPI and virtual functions in C++

Dries Kimpe dkimpe at mcs.anl.gov
Wed Dec 12 13:37:46 CST 2012


Classes/structs that have virtual functions have a different memory layout
than structures/classes without them.

In your code below, you're assuming that the class Pair has a memory
layout of 2 doubles.
This happens to be the case when there are no virtual functions in the
class.

However, if you add a virtual function, the memory layout changes.
The class now also contains information about its runtime type
(i.e. Pair). 

You can fix this by using &p->elem[0] as the address of the data you want
to send/receive.

  Dries

* Hélvio Vairinhos <helvio.vairinhos at gmail.com> [2012-12-12 19:23:12]:

> Hi,

> I came across a strange behaviour of MPI when I try to do a simple
> send/receive of an object of a class which contains virtual functions. I
> wrote a short code to exemplify what happens:


> #include <mpi.h>
> #include <iostream>
> using namespace std;


> class Pair {
>   double elem[2];
> public:
>   Pair();
>   Pair(const double&, const double&);
>   //virtual
>   Pair& operator += (const Pair&);
>   void print();
>   static MPI_Datatype mpi_type;
>   static void Init();
>   static void Finalize();
> };


> Pair::Pair()
> { elem[0]=0.; elem[1]=0.; }

> Pair::Pair(const double& x, const double& y)
> { elem[0]=x; elem[1]=y; }

> Pair& Pair::operator += (const Pair& q)
> { elem[0] += q.elem[0]; elem[1] += q.elem[1]; return *this; }

> void Pair::print()
> { std::cout << "(" << elem[0] << "," << elem[1] << ")" << std::endl; }

> MPI_Datatype Pair::mpi_type;

> void Pair::Init()
> { MPI_Type_contiguous(2,MPI_DOUBLE,&mpi_type);
>   MPI_Type_commit(&mpi_type); }

> void Pair::Finalize()
> { MPI_Type_free(&mpi_type); }


> int main() {
>   int rank;
>   MPI_Init(0,0);
>   MPI_Comm_rank(MPI_COMM_WORLD,&rank);
>   Pair::Init();
>   Pair q;
>   if (rank == 0) {
>     q = Pair(1,2);
>     MPI_Send(&q, 1, Pair::mpi_type, 1, 99, MPI_COMM_WORLD);
>   }
>   if (rank == 1) {
>     q = Pair(3,4);
>     MPI_Status status;
>     MPI_Recv(&q, 1, Pair::mpi_type, 0, 99, MPI_COMM_WORLD, &status);
>     q.print();
>   }
>   Pair::Finalize();
>   MPI_Finalize();
>   return 0;
> }


> I compiled it with mpic++, and ran it on 2 processes. Process 0 simply sends
> the pair q=(1,2) to process 1, which prints the result on the screen. The
> MPI datatype is contiguous with 2 MPI_DOUBLE components.

> The program above behaves just fine, and prints the correct result (1,2).
> However, if I make the operator += virtual within the Pair class (i.e. if I
> uncomment the corresponding line above), then the process 1 prints the
> result (1,4). In other words, process 0 only sends the 1st element of the
> pair. The 2nd element of the pair is only sent if I create an MPI datatype
> with 3 MPI_DOUBLE elements, i.e. if I use
> MPI_Type_contiguous(3,MPI_DOUBLE,&mpi_type). It behaves as if the buffer of
> MPI_Send starts at the address "&q-1" instead of "&q" when the virtual
> keyword is present.

> Does anyone know why this happens, or if I am being careless at some point?
> I need to virtualize some functions in classes like this one, and I would
> like to trust that MPI communication is being done correctly.

> Thank you in advance,

> Helvio Vairinhos
> _______________________________________________
> discuss mailing list     discuss at mpich.org
> To manage subscription options or unsubscribe:
> https://lists.mpich.org/mailman/listinfo/discuss
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 198 bytes
Desc: not available
URL: <http://lists.mpich.org/pipermail/discuss/attachments/20121212/70a1069e/attachment.sig>


More information about the discuss mailing list