尝试用锁抓住C++

Try catch with locks in C++

本文关键字:C++      更新时间:2023-10-16

在Java中:

Lock lock = new ReentrantLock();
try{
lock.lock();
someFunctionLikelyToCauseAnException();
}
catch(e){...}
finally {
lock.unlock();
}

我的问题是,通过上面的这个例子,我们知道锁将始终解锁,因为最终总是执行,但是C++的保证是什么?

mutex m;
m.lock();
someFunctionLikelyToCauseAnException();
/// ????

这将如何工作,为什么?

为此我们使用 RAII 样式的结构std::lock_guard。 当您使用

std::mutex m;
{ // start of some scope
std::lock_guard lg(m);
// stuff
} // end of scope

lg将确保无论作用域离开什么路径,m都将解锁,因为它在作用域退出时被销毁std::lock_guard析构函数将调用unlock

即使抛出异常,堆栈也会被展开(堆栈展开(,并且该过程会破坏lg而反过来又会调用unlock来保证锁被释放。

C++的保证是什么?

与您在 Java 中提到的保证相比,C++中的相关保证的工作方式略有不同。它不是finally 块,而是依赖于在范围退出时发生的自动变量的破坏,因为堆栈帧被解开。无论范围是如何退出的,无论是正常退出还是由于异常,都会发生此堆栈展开

有关此类的方案的首选方法是使用 RAII,例如由std::lock_guard实现。它保存一个传递给其构造函数的mutex对象 - 在其中它调用mutexlock()方法,之后线程拥有互斥锁 - 并且在范围出口处展开堆栈时调用其析构函数 - 在其中它调用mutexunlock()方法,从而释放它。

代码将如下所示:

std::mutex m;
{
std::lock_guard lock(m);
// Everything here is mutex-protected.
}
// Here you are guaranteed the std::mutex is released.

如果在执行受关键部分保护的代码段(即"lock(("和"unlock(("之间的代码(期间引发异常,则表示代码段正在操作的关联对象不再处于有效状态。这可以通过异常触发的堆栈的自动展开来回滚,也可能不会回滚,因为在抛出异常之前可能发生了一些副作用(例如,消息已通过套接字发送,机器已启动(。在这一点上,这里更大的问题不是是否会释放互斥锁(这是改用lock_guard的唯一保证(。在某些情况下,互斥锁仍然被锁定是理想的行为,并且可以在调用方清理所有混乱后显式重置。

我的观点是:这不是语言问题。没有任何语言功能可以保证正确的错误处理。不要把lock_guard和RAII当作灵丹妙药。

相关文章:
  • 没有找到相关文章