On Wed, 2012-11-28 at 14:22 -0600, Hal Finkel wrote:
> > So, to summarize, we have 3 issues:
> > 1) syntax: lower vs upper case and mt->threading.
> > 2) throw an exception if the requested level is not available
> > 3) macro to control availability of MPI[1|2|3] features
In the attached patch:
1 -> done
3 -> not done, I think those macro should be introduced separately, not
in the same commit.
2 -> done, but more precisely:
The ctors that took one level requirement now takes a preferred and a
required level. If the required level could not be provided, an
exception is thrown from the ctor *after* MPI_Finalize is call.
This seems necessary since otherwise, MPI_Abort would get called in the
dtor and the application would quit without MPI_Finalize getting called.
Also, that behavior introduces an error that does not mirror an MPI
error (in the MPI standard). Seems to be the first one, which explain
that I modified the exception hierarchy: We now have a base generalist
exception class (which only take a message) and an derived api_exception
that correspond to the previous exception class (and that contains all
the info related with the MPI standard error). Since the code often ask
a corresponding MPI error code, I choose to bind it to MPI_SUCCESS by
default (indicating that as far as the MPI standard is concerned, there
is no problem) api_exception systematically overrides that code.
I also added a istream>>level operator, is nothing else, it will enable
lexical_cast.
Thanks for reading !
Alain
> > 1) ok, I like it better, too :-)
> >
> > 2) exceptions -> if I understand, it is proposed that we consider
> > the
> > unavailability of the requested level as an error and let the flag
> > 'throw_on_error' decide what to do ?
> > A few small concerns
> > * the MPI standard does not seems to consider this an error, so we
> > do a
>
> The standard does not consider it an error, but it also assumes that the
> caller will check the provided level. This is a bad assumption, and we must
> have a better option ;)
>
> > semantic change (if I understand correctly 8.7 in MPI3)
> > * it is not clear that we are allowed to query the available
> > threading
> > support level (actually, 8.7 seems to indicated that we can't,
> > although
> > there is some weird text associated with the thread_level key of
> > INFO_ENV). That indicates that the user has no way of probing the
> > value
> > before initializing. So if we consider the use case of a user who
> > wants
> > to generally throw on error *and* is willing to adapt to the
> > available
> > threading level, such a change will make that impossible.
>
> Okay, good point, and calling MPI_Init multiple times may not be safe. How
> about this: have the constructors take both a 'preferred' and 'required'
> level; call MPI_Init with the preferred level and throw the exception only if
> the provided level is below the required level. This has the advantage of
> being safe and easy, forcing the programming to think about the options, and
> is not functionally limiting. If a program really has requirements that
> cannot be expressed as a range in this way, they can always set the required
> level to the lowest one and fall back to explicit post-construction tests.
>
> > * we can easily imagine ignoring the result of "provided" level (by
> > default, open MPI only support "single", so in theory, one should not
> > use threads at all with open MPI. Multiple must be explicitly
> > specified
> > during build, and is possibly slow, and there is nothing in between)
>
> Yes; unfortunately, this is a (somewhat common, although certainly not
> universal) implementation deficiency.
>
> > - We cannot fix that with bit magic (allowing stuff like
> > threading::funneled|threadin::mandatory for example) since the
> > numerical
> > value are not specified by the standard.
> > - Adding a boolean flag would be clumsy (we already have one with
> > default value)
> > - we could allow runtime modification of the throw_on_error flag, but
> > then, it is not clear that the most common scenario (and the one
> > matching the MPI-C behavior) would be the easiest.
> >
> > On the other hand, if the user wants to enforce the threading level:
> > mpi::environment env(threading::funneled, true);
> > assert(env.thread_level() >= threading::funneled); /* or an 'if'
> > expression, or we could add an overload to the boost mpi abort to
> > make
> > it more assert like:
> > env.assert(env.thread_level()>=threading::funneled, "requested ...
> > blahh"); */
> > which is basically one more line.
>
> I don't think is good because it still makes it easier to write incorrect
> code than it does to write correct code.
>
> >
> > Any thought ?
> >
> > 3) Ok, actually the BOOST_MPI_HAS_NOARG_INITIALIZATION would fall in
> > that category (the feature is mandatory since MPI2 I think).
> >
> > One last question: in my patch, I am still using MPI_Init instead of
> > the
> > supposedly equivalent MPI_Init(..single..) (keept for backward
> > compatibility) I propose to only use MPI_Init_thread in the
> > implementation.
>
> This is fine with me, so long as we're not keeping compatibility with MPI 1
> implementations. Are we?
>
> Thanks again,
> Hal
>
> >
> > Thanks for reading !
> >
> > Alain
> >
> >
> >
> >
> >
> >
> > On Wed, 2012-11-28 at 09:21 -0600, Hal Finkel wrote:
> > > ----- Original Message -----
> > > > From: "Matthias Troyer" <[email protected]>
> > > > To: "alain miniussi" <[email protected]>, "Discussion of
> > > > Boost.MPI development" <[email protected]>
> > > > Sent: Wednesday, November 28, 2012 8:25:18 AM
> > > > Subject: Re: [Boost-mpi] Thread API
> > > >
> > > > Hi Alain,
> > > >
> > > >
> > > > On Nov 27, 2012, at 5:11 PM, Alain O Miniussi
> > > > <[email protected]>
> > > > wrote:
> > > >
> > > > > Hi,
> > > > >
> > > > > I have a tentative patch that is supposed to provide binding
> > > > > to
> > > > > the MPI
> > > > > thread API. What is the best way to have it reviewed ?
> > > >
> > > > Thank you for your work. I have a few stylistic comments - shall
> > > > I
> > > > send them to you off-list, or shall we discuss them on our new
> > > > mailing list?
> > >
> > > If you don't mind, I'd prefer on-list reviews (even for stylistic
> > > matters). That way we can all benefit from your advice.
> > >
> > > I also have a few comments:
> > >
> > > +enum level {
> > > + /** Only one thread will execute.
> > > + */
> > > + SINGLE = MPI_THREAD_SINGLE,
> > > + /** Only main thread will do MPI calls.
> > >
> > > I think that we should use lower-case enum constant names (single
> > > instead of SINGLE).
> > >
> > > + mt::level mt_level = mt::MULTIPLE;
> > > + boost::mpi::environment env(argc, argv, mt_level);
> > > + mt::level provided = env.thread_level();
> > > + std::cout << "Asked:" << mt_level << ", provided: " << provided
> > > << '\n';
> > > + BOOST_CHECK((provided >= mt::SINGLE && provided <=
> > > mt::MULTIPLE));
> > >
> > > I have a lot of code that looks like this ;) -- but I think that it
> > > could be greatly simplified. How about if the environment
> > > constructor throws an exception if the provided level is less than
> > > the requested level. This way, in the common case where the
> > > program has no fall-back provisions, we don't accidentally
> > > continue under an invalid environment (many programs don't
> > > explicitly check the provided level -- and this obviously leads to
> > > odd behavior and crashes).
> > >
> > > Thanks for working on this!
> > >
> > > -Hal
> > >
> > > >
> > > > > It might be a ticket
> > > > > buthttps://svn.boost.org/trac/boost/report/15the
> > > > > referenced maintainer is Doug
> > > > > (https://svn.boost.org/trac/boost/report/15)
> > > > > and, probably since I have no userid in the tracker, I won't be
> > > > > able to
> > > > > change it.
> > > >
> > > > I'll try to find out how to change it. Doug does not have time
> > > > anymore.
> > > >
> > > > > Just in case, there is a patch in attachment (against rev 81596
> > > > > of
> > > > > trunk).
> > > >
> > > >
> > > > Thank you!
> > > >
> > > > Matthias
> > > >
> > > > _______________________________________________
> > > > Boost-mpi mailing list
> > > > [email protected]
> > > > http://lists.boost.org/mailman/listinfo.cgi/boost-mpi
> > > >
> > >
> >
> >
> >
>
--
Alain Miniussi
Responsable Tech. Centre de Calcul Haute Performance
Obs. de la Côte d'Azur |Mont Gros: +33 4 92 00 30 09
BP 4229 |Sophia : +33 4 83 61 85 44
06304 Nice Cedex 4 |https://crimson.oca.eu
Index: boost/mpi/exception.hpp
===================================================================
--- boost/mpi/exception.hpp (revision 81596)
+++ boost/mpi/exception.hpp (working copy)
@@ -35,14 +35,9 @@
/**
* Build a new @c exception exception.
*
- * @param routine The MPI routine in which the error
- * occurred. This should be a pointer to a string constant: it
- * will not be copied.
- *
- * @param result_code The result code returned from the MPI
- * routine that aborted with an error.
+ * @param message A descriptive message explaining the error.
*/
- exception(const char* routine, int result_code);
+ exception(const std::string& msg);
virtual ~exception() throw();
@@ -54,9 +49,46 @@
return this->message.c_str();
}
+ /**
+ * @brief Retrieve the result code returned from the MPI routine
+ * that reported the error, if any. Sub classes should redefine this
+ * as necessary.
+ */
+ virtual int result_code() const { return MPI_SUCCESS; }
+
+ protected:
+ /// The formatted error message
+ std::string message;
+};
+
+/** @brief Catch-all exception class for MPI errors.
+ *
+ * Instances of this class will be thrown when an MPI error
+ * occurs. MPI failures that trigger these exceptions may or may not
+ * be recoverable, depending on the underlying MPI
+ * implementation. Consult the documentation for your MPI
+ * implementation to determine the effect of MPI errors.
+ */
+class BOOST_MPI_DECL api_exception : public exception
+{
+ public:
+ /**
+ * Build a new @c exception exception.
+ *
+ * @param routine The MPI routine in which the error
+ * occurred. This should be a pointer to a string constant: it
+ * will not be copied.
+ *
+ * @param result_code The result code returned from the MPI
+ * routine that aborted with an error.
+ */
+ api_exception(const char* routine, int result_code);
+
+ virtual ~api_exception() throw();
+
/** Retrieve the name of the MPI routine that reported the error. */
const char* routine() const { return routine_; }
-
+
/**
* @brief Retrieve the result code returned from the MPI routine
* that reported the error.
@@ -80,9 +112,6 @@
/// The failed result code reported by the MPI implementation.
int result_code_;
-
- /// The formatted error message
- std::string message;
};
/**
@@ -95,8 +124,8 @@
{ \
int _check_result = MPIFunc Args; \
if (_check_result != MPI_SUCCESS) \
- boost::throw_exception(boost::mpi::exception(#MPIFunc, \
- _check_result)); \
+ boost::throw_exception(boost::mpi::api_exception(#MPIFunc, \
+ _check_result)); \
}
} } // end namespace boost::mpi
Index: boost/mpi/nonblocking.hpp
===================================================================
--- boost/mpi/nonblocking.hpp (revision 81596)
+++ boost/mpi/nonblocking.hpp (working copy)
@@ -91,7 +91,7 @@
// We don't have a notion of empty requests or status objects,
// so this is an error.
if (index == MPI_UNDEFINED)
- boost::throw_exception(exception("MPI_Waitany", MPI_ERR_REQUEST));
+ boost::throw_exception(api_exception("MPI_Waitany", MPI_ERR_REQUEST));
// Find the iterator corresponding to the completed request.
current = first;
Index: boost/mpi/environment.hpp
===================================================================
--- boost/mpi/environment.hpp (revision 81596)
+++ boost/mpi/environment.hpp (working copy)
@@ -17,9 +17,47 @@
#include <boost/noncopyable.hpp>
#include <boost/optional.hpp>
#include <string>
+#include <iosfwd>
namespace boost { namespace mpi {
+namespace threading {
+/** @brief specify the supported threading level.
+ *
+ * Based on MPI 2 standard/8.7.3
+ */
+enum level {
+ /** Only one thread will execute.
+ */
+ single = MPI_THREAD_SINGLE,
+ /** Only main thread will do MPI calls.
+ *
+ * The process may be multi-threaded, but only the main
+ * thread will make MPI calls (all MPI calls are ``funneled''
+ * to the main thread).
+ */
+ funneled = MPI_THREAD_FUNNELED,
+ /** Only one thread at the time do MPI calls.
+ *
+ * The process may be multi-threaded, and multiple
+ * threads may make MPI calls, but only one at a time:
+ * MPI calls are not made concurrently from two distinct
+ * threads (all MPI calls are ``serialized'').
+ */
+ serialized = MPI_THREAD_SERIALIZED,
+ /** Multiple thread may do MPI calls.
+ *
+ * Multiple threads may call MPI, with no restrictions.
+ */
+ multiple = MPI_THREAD_MULTIPLE
+};
+/** Formated output for threading level. */
+std::ostream& operator<<(std::ostream& out, level l);
+
+/** Formated output for threading level. */
+std::istream& operator>>(std::istream& in, level l);
+
+} // namespace threading
/** @brief Initialize, finalize, and query the MPI environment.
*
* The @c environment class is used to initialize, finalize, and
@@ -62,6 +100,29 @@
* program if it is destructed due to an uncaught exception.
*/
explicit environment(bool abort_on_exception = true);
+ /** Initialize the MPI environment.
+ *
+ * If the MPI environment has not already been initialized,
+ * initializes MPI with a call to @c MPI_Init_thread. Since this
+ * constructor does not take command-line arguments (@c argc and @c
+ * argv), it is only available when the underlying MPI
+ * implementation supports calling @c MPI_Init with @c NULL
+ * arguments, indicated by the macro @c
+ * BOOST_MPI_HAS_NOARG_INITIALIZATION.
+ *
+ * If the required threading support level cannot be provided,
+ * construction will throw and mpi will be finalized.
+ *
+ * @param prefered the prefered level of threading support, will
+ * try to meet that request if possible.
+ *
+ * @param required the minimal level of threading support.
+ *
+ * @param abort_on_exception When true, this object will abort the
+ * program if it is destructed due to an uncaught exception.
+ */
+ explicit environment(threading::level prefered, threading::level required,
+ bool abort_on_exception = true);
#endif
/** Initialize the MPI environment.
@@ -80,6 +141,33 @@
*/
environment(int& argc, char** &argv, bool abort_on_exception = true);
+ /** Initialize the MPI environment.
+ *
+ * If the MPI environment has not already been initialized,
+ * initializes MPI with a call to @c MPI_Init_thread.
+ *
+ * If the required threading support level cannot be provided,
+ * construction will throw and mpi will be finalized.
+ *
+ * @param argc The number of arguments provided in @p argv, as
+ * passed into the program's @c main function.
+ *
+ * @param argv The array of argument strings passed to the program
+ * via @c main.
+ *
+ * @param prefered the prefered level of threading support, will
+ * try to meet that request if possible.
+ *
+ * @param required the minimal level of threading support, this constructor
+ * will throw if the requirement is not fulfilled.
+ *
+ * @param abort_on_exception When true, this object will abort the
+ * program if it is destructed due to an uncaught exception.
+ */
+ environment(int& argc, char** &argv,
+ threading::level prefered, threading::level required,
+ bool abort_on_exception = true);
+
/** Shuts down the MPI environment.
*
* If this @c environment object was used to initialize the MPI
@@ -185,13 +273,26 @@
*/
static std::string processor_name();
+ /** Query the current level of thread support.
+ */
+ static threading::level thread_level();
+
+ /** Are we in the main thread?
+ */
+ static bool main_thread();
+
private:
+ /// Code factorization on ctor.
+ void call_mpi_init(int* argc, char*** argv,
+ threading::level prefered, threading::level required);
+
+private:
/// Whether this environment object called MPI_Init
bool i_initialized;
/// Whether we should abort if the destructor is
bool abort_on_exception;
-
+
/// The number of reserved tags.
static const int num_reserved_tags = 1;
};
Index: libs/mpi/test/mt_level_test.cpp
===================================================================
--- libs/mpi/test/mt_level_test.cpp (revision 0)
+++ libs/mpi/test/mt_level_test.cpp (revision 0)
@@ -0,0 +1,26 @@
+// Copyright (C) 2005-2006 Douglas Gregor <[email protected]>
+
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Test a few basic feature for multi-threading.
+// It is quite basic since the support is dependent
+// on the underlying implementation those threading
+// support is allowed to varry by the MPI standard.
+
+#include <boost/mpi/environment.hpp>
+#include <boost/test/minimal.hpp>
+
+using namespace boost::mpi;
+using namespace std;
+
+int test_main(int argc, char* argv[])
+{
+ using namespace boost::mpi::threading;
+ BOOST_CHECK((single < funneled));
+ BOOST_CHECK((funneled < serialized));
+ BOOST_CHECK((serialized < multiple));
+
+ return 0;
+}
Index: libs/mpi/test/mt_init_failed_test.cpp
===================================================================
--- libs/mpi/test/mt_init_failed_test.cpp (revision 0)
+++ libs/mpi/test/mt_init_failed_test.cpp (revision 0)
@@ -0,0 +1,37 @@
+// Copyright (C) 2005-2006 Alain Miniussi <[email protected]>
+
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Test a few basic feature for multi-threading.
+// It is quite basic since the support is dependent
+// on the underlying implementation those threading
+// support is allowed to varry by the MPI standard.
+
+#include <boost/mpi/environment.hpp>
+#include <boost/mpi/exception.hpp>
+#include <boost/test/minimal.hpp>
+
+namespace mpi = boost::mpi;
+namespace th = boost::mpi::threading;
+using namespace std;
+
+bool do_init(int argc, char* argv[])
+{
+ bool success = false;
+ bool clean_failure = false;
+ try {
+ mpi::environment env(argc, argv, th::multiple, th::multiple);
+ success = env.thread_level() == th::multiple;
+ } catch (mpi::exception& e) {
+ clean_failure = true;
+ }
+ return success || clean_failure;
+}
+
+int test_main(int argc, char* argv[])
+{
+ BOOST_CHECK(do_init(argc,argv));
+ return 0;
+}
Index: libs/mpi/test/Jamfile.v2
===================================================================
--- libs/mpi/test/Jamfile.v2 (revision 81596)
+++ libs/mpi/test/Jamfile.v2 (working copy)
@@ -23,6 +23,9 @@
[ mpi-test broadcast_test : : : 2 17 ]
[ mpi-test gather_test ]
[ mpi-test is_mpi_op_test : : : 1 ]
+ [ mpi-test mt_level_test : : : 1 4 ]
+ [ mpi-test mt_init_test : : : 1 4 ]
+ [ mpi-test mt_init_failed_test : : : 1 4 ]
# Note: Microsoft MPI fails nonblocking_test on 1 processor
[ mpi-test nonblocking_test ]
[ mpi-test reduce_test ]
Index: libs/mpi/test/mt_init_test.cpp
===================================================================
--- libs/mpi/test/mt_init_test.cpp (revision 0)
+++ libs/mpi/test/mt_init_test.cpp (revision 0)
@@ -0,0 +1,26 @@
+// Copyright (C) 2005-2006 Alain Miniussi <[email protected]>
+
+// Use, modification and distribution is subject to the Boost Software
+// License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
+// http://www.boost.org/LICENSE_1_0.txt)
+
+// Test a few basic feature for multi-threading.
+// It is quite basic since the support is dependent
+// on the underlying implementation those threading
+// support is allowed to varry by the MPI standard.
+
+#include <boost/mpi/environment.hpp>
+#include <boost/test/minimal.hpp>
+
+using namespace boost::mpi;
+using namespace std;
+
+int test_main(int argc, char* argv[])
+{
+ // just test for one value, I could not find the doc in mpi.jam
+ // to pass params through argc/argv
+ namespace th = threading;
+ boost::mpi::environment env(argc, argv, th::multiple, th::single);
+ BOOST_CHECK((env.thread_level() >= th::single));
+ return 0;
+}
Index: libs/mpi/src/request.cpp
===================================================================
--- libs/mpi/src/request.cpp (revision 81596)
+++ libs/mpi/src/request.cpp (working copy)
@@ -42,13 +42,13 @@
// one when throwing the exception.
if (stats[0].MPI_ERROR == MPI_SUCCESS
|| stats[0].MPI_ERROR == MPI_ERR_PENDING)
- boost::throw_exception(exception("MPI_Waitall", stats[1].MPI_ERROR));
+ boost::throw_exception(api_exception("MPI_Waitall", stats[1].MPI_ERROR));
else
- boost::throw_exception(exception("MPI_Waitall", stats[0].MPI_ERROR));
+ boost::throw_exception(api_exception("MPI_Waitall", stats[0].MPI_ERROR));
} else if (error_code != MPI_SUCCESS) {
// There was an error somewhere in the MPI_Waitall call; throw
// an exception for it.
- boost::throw_exception(exception("MPI_Waitall", error_code));
+ boost::throw_exception(api_exception("MPI_Waitall", error_code));
}
// No errors. Returns the first status structure.
@@ -85,13 +85,13 @@
// one when throwing the exception.
if (stats[0].MPI_ERROR == MPI_SUCCESS
|| stats[0].MPI_ERROR == MPI_ERR_PENDING)
- boost::throw_exception(exception("MPI_Testall", stats[1].MPI_ERROR));
+ boost::throw_exception(api_exception("MPI_Testall", stats[1].MPI_ERROR));
else
- boost::throw_exception(exception("MPI_Testall", stats[0].MPI_ERROR));
+ boost::throw_exception(api_exception("MPI_Testall", stats[0].MPI_ERROR));
} else if (error_code != MPI_SUCCESS) {
// There was an error somewhere in the MPI_Testall call; throw
// an exception for it.
- boost::throw_exception(exception("MPI_Testall", error_code));
+ boost::throw_exception(api_exception("MPI_Testall", error_code));
}
// No errors. Returns the second status structure if the send has
Index: libs/mpi/src/exception.cpp
===================================================================
--- libs/mpi/src/exception.cpp (revision 81596)
+++ libs/mpi/src/exception.cpp (working copy)
@@ -10,20 +10,27 @@
namespace boost { namespace mpi {
-exception::exception(const char* routine, int result_code)
- : routine_(routine), result_code_(result_code)
+exception::exception(const std::string& msg)
+ : message(msg)
{
+}
+
+exception::~exception() throw() { }
+
+
+api_exception::api_exception(const char* routine, int result_code)
+ : exception(routine), routine_(routine), result_code_(result_code)
+{
// Query the MPI implementation for its reason for failure
char buffer[MPI_MAX_ERROR_STRING];
int len;
MPI_Error_string(result_code, buffer, &len);
// Construct the complete error message
- message.append(routine_);
message.append(": ");
message.append(buffer, len);
}
-exception::~exception() throw() { }
+api_exception::~api_exception() throw() { }
} } // end namespace boost::mpi
Index: libs/mpi/src/environment.cpp
===================================================================
--- libs/mpi/src/environment.cpp (revision 81596)
+++ libs/mpi/src/environment.cpp (working copy)
@@ -8,23 +8,102 @@
#include <boost/mpi/environment.hpp>
#include <boost/mpi/exception.hpp>
#include <boost/mpi/detail/mpi_datatype_cache.hpp>
+#include <boost/algorithm/string.hpp>
#include <cassert>
#include <exception>
#include <stdexcept>
+#include <ostream>
+#include <sstream>
namespace boost { namespace mpi {
+namespace threading {
+std::ostream&
+operator<<(std::ostream& out, level l)
+{
+ switch(l) {
+ case single:
+ out << "single";
+ break;
+ case funneled:
+ out << "funneled";
+ break;
+ case serialized:
+ out << "serialized";
+ break;
+ case multiple:
+ out << "multiple";
+ break;
+ default:
+ out << "<level error>[" << int(l) << ']';
+ break;
+ }
+ return out;
+}
+std::istream&
+operator>>(std::istream& in, level l)
+{
+ std::string buf;
+ in >> buf;
+ if (in.good()) {
+ boost::to_upper(buf);
+ if (buf == "SINGLE") {
+ l = single;
+ } else if (buf == "FUNNELED") {
+ l = funneled;
+ } else if (buf == "SERIALIZED") {
+ l = serialized;
+ } else if (buf == "MULTIPLE") {
+ l = multiple;
+ } else {
+ in.setstate(std::ios_base::failbit);
+ }
+ }
+ return in;
+}
+} // namespace threading
+
+void
+environment::call_mpi_init(int* argc, char*** argv,
+ threading::level prefered, threading::level required)
+{
+ BOOST_ASSERT(required <= prefered);
+ if (!initialized()) {
+ int provided;
+ BOOST_MPI_CHECK_RESULT(MPI_Init_thread,
+ (argc, argv, int(prefered), &provided ));
+ if (threading::level(provided) < required) {
+ // no cleanup necessary in dtor
+ i_initialized = false;
+ // we need to finalize right here so that the
+ // the aplication does not leave without finalization.
+ BOOST_MPI_CHECK_RESULT(MPI_Finalize, ());
+ std::ostringstream fmt;
+ fmt << "Asked for prefered threading support level '"
+ << prefered << "' with minimum required '"
+ << required << "', got '" << threading::level(provided) << "'\n";
+ boost::throw_exception(boost::mpi::exception(fmt.str()));
+ } else {
+ i_initialized = true;
+ }
+ }
+ MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
+}
+
#ifdef BOOST_MPI_HAS_NOARG_INITIALIZATION
environment::environment(bool abort_on_exception)
: i_initialized(false),
abort_on_exception(abort_on_exception)
{
- if (!initialized()) {
- BOOST_MPI_CHECK_RESULT(MPI_Init, (0, 0));
- i_initialized = true;
- }
+ call_mpi_init(0, 0, threading::single, threading::single);
+}
- MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
+environment::environment(threading::level prefered, threading::level required,
+ bool abort_on_exception)
+ : i_initialized(false),
+ abort_on_exception(abort_on_exception)
+{
+ call_mpi_init(0, 0, prefered, required);
}
#endif
@@ -32,12 +111,16 @@
: i_initialized(false),
abort_on_exception(abort_on_exception)
{
- if (!initialized()) {
- BOOST_MPI_CHECK_RESULT(MPI_Init, (&argc, &argv));
- i_initialized = true;
- }
+ call_mpi_init(&argc, &argv, threading::single, threading::single);
+}
- MPI_Errhandler_set(MPI_COMM_WORLD, MPI_ERRORS_RETURN);
+environment::environment(int& argc, char** &argv,
+ threading::level prefered, threading::level required,
+ bool abort_on_exception)
+ : i_initialized(false),
+ abort_on_exception(abort_on_exception)
+{
+ call_mpi_init(&argc, &argv, prefered, required);
}
environment::~environment()
@@ -122,4 +205,20 @@
return std::string(name, len);
}
+threading::level environment::thread_level()
+{
+ int level;
+
+ BOOST_MPI_CHECK_RESULT(MPI_Query_thread, (&level));
+ return static_cast<threading::level>(level);
+}
+
+bool environment::main_thread()
+{
+ int isit;
+
+ BOOST_MPI_CHECK_RESULT(MPI_Is_thread_main, (&isit));
+ return bool(isit);
+}
+
} } // end namespace boost::mpi
_______________________________________________
Boost-mpi mailing list
[email protected]
http://lists.boost.org/mailman/listinfo.cgi/boost-mpi