MPI_Send C ++中的MPI_Recv段错误

时间:2013-12-31 20:43:37

标签: c++ mpi

我在MPI中编写了一个简单的程序,它在处理器之间发送和接收消息,但运行时出现分段错误。

这是我的整个代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string>
#include <string.h>
#include <strings.h>
#include <sstream>
#include<mpi.h>
using namespace std;
class Case {
public:
    int value;
    std::stringstream sta;
};
int main(int argc, char **argv) {
     int rank,size;
     MPI::Init(argc,argv);
     rank=MPI::COMM_WORLD.Get_rank();
     size=MPI::COMM_WORLD.Get_size();
     if(rank==0){
        Case *s=new Case();
        s->value=1;
        s->sta<<"test";
        cout<<"\nInside send before copy value  :"<<s->value;
        fflush(stdout);
        cout<<"\nInside send before copy data  :"<<s->sta.str();
        fflush(stdout);
        Case scpy;
        scpy.value=s->value;
        scpy.sta<<(s->sta).rdbuf();
        cout<<"\nInside send after copy value  :"<<scpy.value;
        cout<<"\nInside send after copy value  :"<<scpy.sta.str();
        MPI::COMM_WORLD.Send(&scpy,sizeof(Case),MPI::BYTE,1,23);
     }
     MPI::COMM_WORLD.Barrier();
     if(rank==1){
        Case r;
        MPI::COMM_WORLD.Recv(&r,sizeof(Case),MPI::BYTE,0,23);
        cout<<"\nRecieve value"<<r.value;
        fflush(stdout);
        cout<<"\nRecieve data"<<r.sta;
        fflush(stdout);
     }
     MPI::Finalize();
     return 0;
}

我收到以下错误消息,我无法弄清楚这个程序有什么问题。
有人可以解释一下吗?  

Inside send before copy value  :1
Inside send before copy data  :test
Inside send after copy value  :1

Recieve value1
Recieve data0xbfa5d6b4[localhost:03706] *** Process received signal ***
[localhost:03706] Signal: Segmentation fault (11)
[localhost:03706] Signal code: Address not mapped (1)
[localhost:03706] Failing at address: 0x8e1a210
[localhost:03706] [ 0] [0xe6940c]
[localhost:03706] [ 1] /usr/lib/libstdc++.so.6(_ZNSt18basic_stringstreamIcSt11char_traitsIcESaIcEED1Ev+0xc6) [0x6a425f6]
[localhost:03706] [ 2] ./a.out(_ZN4CaseD1Ev+0x14) [0x8052d8e]
[localhost:03706] [ 3] ./a.out(main+0x2f9) [0x804f90d]
[localhost:03706] [ 4] /lib/libc.so.6(__libc_start_main+0xe6) [0x897e36]
[localhost:03706] [ 5] ./a.out() [0x804f581]
[localhost:03706] *** End of error message ***
--------------------------------------------------------------------------
mpirun noticed that process rank 1 with PID 3706 on node localhost.localdomain exited on signal 11 (Segmentation fault).
-------------------------------------------------------------------------- 

1 个答案:

答案 0 :(得分:3)

问题

我认为问题在于:

MPI::COMM_WORLD.Send(&scpy,sizeof(Case),MPI::BYTE,1,23);

将一个Case结构的副本发送给接收者,但它发送的字节的原始副本并不是很有用。 std :: stringstream类将包含指向用于存储字符串的实际内存的指针,因此此代码将:

  1. 发送一个指向接收器的指针(包含对接收器毫无意义的地址)
  2. 不发送字符串的实际内容。
  3. 接收器在尝试取消引用无效指针时会发出错误。

    修复1

    解决此问题的一种方法是自己发送角色数据。

    在这种方法中,您将发送一条指向std :: stringstream :: str():: c_str()且长度为std :: stringstream :: str():: size()* sizeof(char)的消息。

    修复2

    一种替代方法似乎更适合您尝试使用MPI和字符串的方式是使用Boost库。 Boost包含MPI函数,可以自动为您序列化数据。

    有关Boost和MPI的有用教程on the boost website。 以下是该教程中执行类似任务的示例代码:

    #include <boost/mpi.hpp>
    #include <iostream>
    #include <string>
    #include <boost/serialization/string.hpp>
    namespace mpi = boost::mpi;
    
    int main(int argc, char* argv[]) 
    {
      mpi::environment env(argc, argv);
      mpi::communicator world;
    
      if (world.rank() == 0) {
        world.send(1, 0, std::string("Hello"));
        std::string msg;
        world.recv(1, 1, msg);
        std::cout << msg << "!" << std::endl;
      } else {
        std::string msg;
        world.recv(0, 0, msg);
        std::cout << msg << ", ";
        std::cout.flush();
        world.send(0, 1, std::string("world"));
      }
    
      return 0;
    }