c++ - Is this code exceptions handled correctly? -
in following code, possible event throws exception , may not handled in handler, (rare still case)
i want keep "lck2" unlocked while executing event, because don't want main thread block "mtx2", reason nothing more optimization.
can guarantee "lck2" released in catch block? or there runtime exceptions , therefore may cause deadlocks or unexpected behavior?
std::unique_lock<std::mutex>lck2(mtx2); // lock used waiting event. while (_isrunning) { try { while (_isrunning) { // cvar2 condition variable cvar2.wait(lck2, [&] {return invoke; }); // wait until invoke == true if (invoke) // if event must invoked { lck2.unlock(); onevent(this, someproperty); // may throw exception lck2.lock(); invoke = false; // execution completed } } } catch (...) // need keep thread alive @ costs! { lck2.lock(); // safe? invoke = false; } }
a rewrite of code more appropriate, make easier developer work on code. show 2 rewrites:
first, (bad)
while (true) { try { { std::lock_guard<std::mutex> lckx(mtx2); if(!_isrunning) break; //out of main loop } bool should_invoke = false; { std::unique_lock<std::mutex> lck2(mtx2); cvar2.wait(lck2, [&] {return invoke; }); should_invoke = invoke; } if (should_invoke) // if event must invoked { onevent(this, someproperty); // may throw exception { std::lock_guard<std:mutex> lckx(mtx2); invoke = false; // execution completed } } } catch (...) // need keep thread alive @ costs! { std::lock_guard<std:mutex> lckx(mtx2); invoke = false; } }
second, (good)
breaking (first) code smaller functional units; note expression
cvar2.wait(lck2, [&]{ return invoke; })suspend execution , return if woken andinvoketrue, can infer need expression wait. hence can discard superfluous use ofinvoke. hence have:void do_work(){ while(is_running()){ try{ wait_for_invocation(); onevent(this, someproperty); // may throw exception set_invocation_state(false); catch(...){ set_invocation_state(false); } } }where helpers defined:
bool is_running(){ std::lock_guard<std::mutex> lckx(mtx2); return _isrunning; } void wait_for_invocation(){ std::unique_lock<std::mutex> lck2(mtx2); cvar2.wait(lck2, [&] {return invoke; }); } void set_invocation_state(bool state){ std::lock_guard<std::mutex> lckx(mtx2); invoke = state; }
Comments
Post a Comment