Boost MPI und Exceptions [Schon erledigt. Ich bin so blind.]


  • Mod

    edit: Erledigt, sehe unten. Für interessierte lasse ich es mal stehen, vielleicht hilft es mal einem anderen Verwirrten.

    Ich stelle gerade einen MPI-Code auf Boost MPI um. Eigentlich ist das schöne an Boost MPI ja, dass es RAII benutzt und daher idiotensicher (vermutlich bin ich gerade der sprichwörtliche größere Idiot) auch bei komplizierten Abläufen einsetzbar ist. Daher ist folgendes Programm gültig, obwohl man kein Finalize aufruft:

    #include <boost/mpi.hpp>
    
    int main(int argc, char* argv[])
    {
      boost::mpi::environment e;
    }
    

    Nun scheitert es aber schon an der einfachsten Exception:

    #include <boost/mpi.hpp>
    
    int main(int argc, char* argv[])
    {
      try
        {
          boost::mpi::environment e(argc, argv);
          throw 0;
        }
      catch (int)
        {
        }
    }
    

    Gibt mir bei einen Laufzeitfehler (hier 4 Prozesse, der Prozess welcher den Fehler wirft ist nicht immer der gleiche):

    --------------------------------------------------------------------------
    MPI_ABORT was invoked on rank 1 in communicator MPI_COMM_WORLD 
    with errorcode -1.
    
    NOTE: invoking MPI_ABORT causes Open MPI to kill all MPI processes.
    You may or may not see output from other processes, depending on
    exactly when Open MPI kills them.
    --------------------------------------------------------------------------
    --------------------------------------------------------------------------
    mpirun has exited due to process rank 1 with PID 25839 on
    node milhouse exiting without calling "finalize". This may
    have caused other processes in the application to be
    terminated by signals sent by mpirun (as reported here).
    --------------------------------------------------------------------------
    

    Wenn ich das environment selber nachbaue:

    #include <mpi.h>
    
    struct env
    {
      env(int &argc, char **&argv)
      {
        MPI_Init(&argc, &argv);
      }
      ~env() 
      {
        MPI_Finalize();
      }
    };
    
    int main(int argc, char *argv[])
    {
      try
        {
          env e(argc, argv);
          throw 1;
        }
      catch (int i)
        {
          return i;      
        }
      return 0;
    }
    

    Dann funktioniert es fehlerlos! 😮 😕

    Komischerweise funktioniert Boost MPI wenn man das environment einen Scope höher definiert:

    #include <boost/mpi.hpp>
    
    int main(int argc, char* argv[])
    {
      boost::mpi::environment e(argc, argv);
      try
       {
         throw 0;
       }
      catch (int)
       {
       }
    }
    

    Das ist zwar eine Lösung, aber das kann doch nicht sein! Was geht hier vor? Hier werden doch die Regeln der Stackabräumung irgendwie verletzt.

    Laut Doku ist das environment in Boost MPI ziemlich genau das was ich selber gebastelt habe:

    ~environment();

    Shuts down the MPI environment.

    If this environment object was used to initialize the MPI environment, and the MPI environment has not already been shut down (finalized), this destructor will shut down the MPI environment. Under normal circumstances, this only involves invoking MPI_Finalize. However, if destruction is the result of an uncaught exception and the abort_on_exception parameter of the constructor had the value true, this destructor will invoke MPI_Abort with MPI_COMM_WORLD to abort the entire MPI program with a result code of -1.

    Da steht zwar was von ungefangenen Exceptions, aber diese hier wurde doch gefangen!

    edit: Erledigt. Das mit der ungefangenen Exception war es natürlich doch. Wenn das environment-Objekt zerstört wird, dann ist die Exception ja selber noch nicht gefangen. So ein einfacher Logikfehler und ich komme erst drauf, nachdem ich diesen Roman hier geschrieben habe. Lösungsmöglichkeiten sind daher entweder die Definition im Scope um das catch (siehe oben) oder im Konstruktor den entsprechenden Parameter auf 0 zu setzen.



  • Ich kenne mich mit Boost MPI nicht aus.

    So wie ich das aber verstanden habe mag environment es nicht, wenn der Dtor aufgerufen wird während es eine uncaught exception gibt. In deinem 1. Code gibt es aber eine - throw 0; ist solange uncaught bis der dtor von environment beendet ist und der catch Block ausgeführt wird.



  • Warum verhält sich das Ding denn anders, falls es im Dtor gerade eine ungefangene Exception gibt? Das klingt ziemlich seltsam 😮


  • Mod

    Kellerautomat schrieb:

    Warum verhält sich das Ding denn anders, falls es im Dtor gerade eine ungefangene Exception gibt? Das klingt ziemlich seltsam 😮

    Ich spekuliere mal, die Absicht dahinter ist, dass man das environment immer im obersten Scope von main definieren soll. Wenn dort eine noch ungefangene Exception auftaucht, dann möchte man das Programm eben so laut es geht krachen lassen :p . Dadurch beenden dann nämlich auch die anderen Prozesse, die sonst vielleicht gar nichts von dem Fehler mitbekommen hätten. Immerhin haben die Entwickler dran gedacht, dass man es auch anders wollen könnte, und haben es konfigurierbar gemacht.


Anmelden zum Antworten