是否正确处理了此代码异常?
Is this code exceptions handled correctly?
在下面的代码中,事件可能会抛出异常,并且可能不会在 even handler 中处理,(很少见,但仍然如此)
我想在执行事件时保持 "lck2" 解锁,因为我不想 "mtx2" 的主线程块,原因无非是优化。
我能保证"lck2"总是在catch块中释放吗?或者可能存在运行时异常,因此可能导致死锁或某些意外行为?
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;
}
}
重写您的代码可能更合适,以便其他开发人员更容易处理代码。我将向您展示两个重写:
首先,(差)
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; })
将暂停执行,只有 return 如果被唤醒 并且 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;
}
在下面的代码中,事件可能会抛出异常,并且可能不会在 even handler 中处理,(很少见,但仍然如此)
我想在执行事件时保持 "lck2" 解锁,因为我不想 "mtx2" 的主线程块,原因无非是优化。
我能保证"lck2"总是在catch块中释放吗?或者可能存在运行时异常,因此可能导致死锁或某些意外行为?
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;
}
}
重写您的代码可能更合适,以便其他开发人员更容易处理代码。我将向您展示两个重写:
首先,(差)
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; })
将暂停执行,只有 return 如果被唤醒 并且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; }