dune-common  2.2.0
mpiguard.hh
Go to the documentation of this file.
00001 // -*- tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
00002 // vi: set et ts=8 sw=4 sts=4:
00003 
00011 #ifndef DUNE_COMMON_MPIGUARD_HH
00012 #define DUNE_COMMON_MPIGUARD_HH
00013 
00014 #include <dune/common/mpihelper.hh>
00015 #include <dune/common/collectivecommunication.hh>
00016 #include <dune/common/mpicollectivecommunication.hh>
00017 #include <dune/common/exceptions.hh>
00018 
00019 namespace Dune
00020 {
00021 
00022 #ifndef DOXYGEN
00023 
00024     /*
00025       Interface class for the communication needed by MPIGuard
00026     */
00027     struct GuardCommunicator
00028     {
00029         // cleanup
00030         virtual ~GuardCommunicator() {};
00031         // all the communication methods we need
00032         virtual int rank() = 0;
00033         virtual int size() = 0;
00034         virtual int sum(int i) = 0;
00035         // create a new GuardCommunicator pointer
00036         template <class C>
00037         static GuardCommunicator * create(const C & c);
00038     };
00039 
00040     namespace {
00041         /*
00042           templated implementation of different communication classes
00043          */
00044         // the default class will always fail, due to the missing implementation of "sum"
00045         template <class Imp>
00046         struct GenericGuardCommunicator
00047             : public GuardCommunicator
00048         {};
00049         // specialization for CollectiveCommunication
00050         template <class T>
00051         struct GenericGuardCommunicator< CollectiveCommunication<T> >
00052             : public GuardCommunicator
00053         {
00054             const CollectiveCommunication<T> comm;
00055             GenericGuardCommunicator(const CollectiveCommunication<T> & c) :
00056                 comm(c) {}
00057             virtual int rank() { return comm.rank(); };
00058             virtual int size() { return comm.size(); };
00059             virtual int sum(int i) { return comm.sum(i); }
00060         };
00061         
00062 #if HAVE_MPI
00063         // specialization for MPI_Comm
00064         template <>
00065         struct GenericGuardCommunicator<MPI_Comm>
00066             : public GenericGuardCommunicator< CollectiveCommunication<MPI_Comm> >
00067         {
00068             GenericGuardCommunicator(const MPI_Comm & c) :
00069                 GenericGuardCommunicator< CollectiveCommunication<MPI_Comm> >(
00070                     CollectiveCommunication<MPI_Comm>(c)) {}
00071         };
00072 #endif
00073     } // anonymous namespace
00074 
00075     template<class C>
00076     GuardCommunicator * GuardCommunicator::create(const C & comm)
00077     {
00078         return new GenericGuardCommunicator<C>(comm);
00079     }
00080 #endif
00081 
00085     class MPIGuardError : public ParallelError {};
00086     
00119     class MPIGuard
00120     {
00121         GuardCommunicator * comm_;
00122         bool active_;
00123 
00124         // we don't want to copy this class
00125         MPIGuard (const MPIGuard &);
00126 
00127     public:
00132         MPIGuard (bool active=true) :
00133             comm_(GuardCommunicator::create(
00134                     MPIHelper::getCollectiveCommunication())),
00135             active_(active)
00136         {}
00137 
00143         MPIGuard (MPIHelper & m, bool active=true) :
00144             comm_(GuardCommunicator::create(
00145                     m.getCollectiveCommunication())),
00146             active_(active)
00147         {}
00148 
00159         template <class C>
00160         MPIGuard (const C & comm, bool active=true) :
00161             comm_(GuardCommunicator::create(comm)),
00162             active_(active)
00163         {}
00164         
00167         ~MPIGuard()
00168         {
00169             if (active_)
00170             {
00171                 active_ = false;
00172                 finalize(false);
00173             }
00174             delete comm_;
00175         }
00176         
00181         void reactivate() {
00182             if (active_ == true)
00183                 finalize();
00184             active_ = true;
00185         }
00186         
00197         void finalize(bool success = true)
00198         {
00199             int result = success?0:1;
00200             bool was_active = active_;
00201             active_ = false;
00202             result = comm_->sum(result);
00203             if (result>0 && was_active)
00204             {
00205                 DUNE_THROW(MPIGuardError, "Terminating process "
00206                     << comm_->rank() << " due to "
00207                     << result << " remote error(s)");
00208             }
00209         }
00210     };
00211 
00212 }
00213 
00214 #endif // DUNE_COMMON_MPIGUARD_HH