是否正确处理了此代码异常?

Is this code exceptions handled correctly?

本文关键字:异常 代码 正确处理 是否      更新时间:2023-10-16

在下面的代码中,事件可能会引发异常,并且可能无法在处理程序中处理,(很少见,但仍然如此(

我想在执行事件时保持"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; })将暂停执行,并且只有在唤醒并且invoketrue时才返回,然后我们可以推断我们只需要该表达式等待。因此,我们可以放弃多余的使用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;
    }