0

I'm trying to start up another process that calls the first and joins it via MPI, but I'm getting an access violation I can't figure out. I think the code should be pretty self explanatory, the access violation hits on the MPI_COMM_ACCEPT line. I think everything looks more or less in line, it should work, but it won't.

If I'm going about this all wrong and there's a simpler way, let me know. I'm not using mpiexec as I'm trying to do this w/in a test framework that constructs the whole mess, but if that makes way more sense, then just tell me I've made a botch of it.

#include <windows.h>
#include <AtlBase.h>
#include <atlconv.h>
#include <iostream>
#include "mpi.h"
#include <string>
int main(int argc, char** argv)
{
    MPI_Init(&argc, &argv);
    MPI_Comm intercomm;
    if (argc == 1)
    {
        PROCESS_INFORMATION pi;
        STARTUPINFO si;
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));
        std::string x = std::string(argv[0]);
        x += " ";
        x += std::to_string(1);
        int res = CreateProcess(NULL, CA2T(x.c_str()), NULL, NULL, false, NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW, NULL, NULL, &si, &pi);
        std::cout << res <<std::endl;
        MPI_Open_port(MPI_INFO_NULL, "A");
        MPI_Comm_accept("A", MPI_INFO_NULL, 0, MPI_COMM_SELF,&intercomm);
        std::cout << MPI_Comm_size(intercomm, &res);
        std::cout << res;
    }
    else
    {
        MPI_Comm_connect("A", MPI_INFO_NULL, 0, MPI_COMM_SELF, &intercomm);
    }
    MPI_Finalize();
    // }
}

Edit: WORKS! THIS WAS VERY FRUSTRATING BUT IT WORKS!

#include <cstdlib>
#include <ctime>
#include <iomanip>
#include <iostream>
#include <mpi.h>
#include <windows.h>
#include <AtlBase.h>
#include <atlconv.h>
#include <iostream>
#include "mpi.h"
#include <string>
int main(int argc, char** argv)
{
    char myPort[MPI_MAX_PORT_NAME];
    MPI_Init(&argc, &argv);
    MPI_Comm intercomm;
    if (argc == 1)
    {
        PROCESS_INFORMATION pi;
        STARTUPINFO si;
        ZeroMemory(&si, sizeof(si));
        si.cb = sizeof(si);
        ZeroMemory(&pi, sizeof(pi));
        MPI_Open_port(MPI_INFO_NULL, myPort);
        std::string x = std::string(argv[0])+" \""+myPort+"\"";
        std::cout <<"OLDPROCESS:" << x << std::endl;
        int res = CreateProcess(NULL, CA2T(x.c_str()), NULL, NULL, false, NORMAL_PRIORITY_CLASS , NULL, NULL, &si, &pi);
        MPI_Comm_accept(myPort, MPI_INFO_NULL, 0, MPI_COMM_SELF, &intercomm);
        std::cout << MPI_Comm_size(intercomm, &res);
    }
    else
    {
        std::cout << "NEWPROCESS:"<<argv[1] << std::endl;
        strcpy_s(myPort,argv[1]);
        MPI_Comm_connect(myPort, MPI_INFO_NULL, 0, MPI_COMM_SELF, &intercomm);
    }
    MPI_Finalize();
    // }
}
Carbon
  • 3,828
  • 3
  • 24
  • 51

1 Answers1

2

You are not using MPI_Open_port properly. The second argument in your case is the string literal "A" while the function expects it to be a character array of at least MPI_MAX_PORT_NAME elements. This is an output argument where the actual port name gets written to. Passing a constant string results in an access violation as string constants are usually stored in read-only segments on modern OSes.

Also, the first argument to both MPI_Comm_accept and MPI_Comm_connect should be the port name as returned by MPI_Open_port. As the port name might differ every time, MPI allows it to be registered under a well-known service name using MPI_Publish_name. That well-known name can then be passed to MPI_Lookup_name to obtain the port. Getting the name registration to work properly is a bit tricky with some MPI implementations, therefore for processes that run on the same node one could simply write the port address to a file. You should obviously do this before calling CreateProcess.

Hristo Iliev
  • 72,659
  • 12
  • 135
  • 186
  • I think I'm getting closer - shouldn't the above code do it? But the two aren't quite meeting... – Carbon May 09 '17 at 19:23
  • GOT IT! THANK YOU – Carbon May 09 '17 at 19:26
  • And for those going through this behind me, the last thing you need is an intercomm_merge. There is life beyond MPI_COMM_WORLD! – Carbon May 09 '17 at 20:22
  • I think you are trying to reimplement what I've described [here](http://stackoverflow.com/a/41506324/1374437) just without using `MPI_Comm_spawn`. – Hristo Iliev May 10 '17 at 07:58
  • Yeah, I think it's similar. To those reading this, if you can, use mpiexec, this ain't easy. I'm doing it the not very fun way as MSMPI doesn't support MPI_COMM_SPAWN. – Carbon May 10 '17 at 12:45