在下面的代码中,事件可能抛出异常,甚至可能在处理程序中处理,(很少见,但仍然如此)
我希望在执行事件时保持“lck2”解锁,因为我不希望主线程块为“mtx2”,原因只不过是优化。
我可以保证在catch块中始终释放“lck2”吗?或者可能存在运行时异常,因此可能导致死锁或某些意外行为?
std::unique_lock<std::mutex>lck2(mtx2); // lock used for waiting for event.
while (_isRunning)
{
try
{
while (_isRunning)
{
// cvar2 is condition variable
cvar2.wait(lck2, [&] {return invoke; }); // wait until invoke == true
if (invoke) // if event must be invoked
{
lck2.unlock();
OnEvent(this, someproperty); // may throw exception
lck2.lock();
invoke = false; // execution completed
}
}
}
catch (...) // we need to keep this thread alive at all costs!
{
lck2.lock(); // is this safe?
invoke = false;
}
}
答案 0 :(得分:1)
重写代码可能更合适,以便让其他开发人员更容易处理代码。我将告诉你两个重写:
while (true)
{
try
{
{
std::lock_guard<std::mutex> lckx(mtx2);
if(!_isRunning)
break; //out of the 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 be invoked
{
OnEvent(this, someproperty); // may throw exception
{
std::lock_guard<std:mutex> lckx(mtx2);
invoke = false; // execution completed
}
}
}
catch (...) // we need to keep this thread alive at all costs!
{
std::lock_guard<std:mutex> lckx(mtx2);
invoke = false;
}
}
将(第一个)代码分解为更小的功能单元;我们还注意到表达式cvar2.wait(lck2, [&]{ return invoke; })
将暂停执行,只有在醒来并且 invoke
为true
时才会返回,然后我们可以推断出我们只需要该表达式等待。因此,我们可以放弃invoke
的多余用法。因此我们有:
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);
}
}
}
定义帮助者的地方:
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;
}