Since you are using C ++, why not use RAII? You will still need to verify the use of re-participation, but RAII will greatly simplify the situation. Combined with the larsmans mutex and the Raedwald exception in NDEBUG :
struct Frobber { Frobber() { assert(mtx.try_lock()); #ifndef NDEBUG try { // in case prepare throws #endif prepare(); #ifndef NDEBUG } catch (...) { mtx.unlock(); throw; } #endif } void something(); // And the other actions that can be performed between preparation and finishing. ~Frobber() { finish(); #ifndef NDEBUG mtx.unlock(); #endif } private: #ifndef NDEBUG static boost::mutex mtx; #endif Frobber(Frobber const&); // not defined; 0x: = delete Frobber& operator=(Frobber const&); // not defined; 0x: = delete }; #ifndef NDEBUG boost::mutex Frobber::mtx; #endif void example() { Frobber blah; // instead of prepare() blah.something(); // implicit finish() }
Inside the example, you simply cannot do something without preliminary preparation, and completion will always occur, even if an exception is thrown.
Side note about NDEBUG: if you use it this way, make sure it is either always defined or always undefined in all translation units, as opposed to how it is used for approval (allowing you to define it and undefined at different points).
source share