尝试使用C++中的锁定捕获

Bri*_*dia 38 c++ multithreading operating-system locking

在Java中:

Lock lock = new ReentrantLock();
try{
  lock.lock();
  someFunctionLikelyToCauseAnException();
}
catch(e){...}
finally {
  lock.unlock();
}
Run Code Online (Sandbox Code Playgroud)

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

mutex m;
m.lock();
someFunctionLikelyToCauseAnException();
/// ????
Run Code Online (Sandbox Code Playgroud)

这将如何工作?为什么?

Nat*_*ica 61

为此,我们使用RAII风格的结构std::lock_guard.当你使用

std::mutex m;
{ // start of some scope
    std::lock_guard lg(m);
    // stuff
} // end of scope
Run Code Online (Sandbox Code Playgroud)

lg将确保m无论在什么路径下保留将被解锁,因为它在范围出口处被销毁并且std::lock_guard析构函数将调用unlock

即使抛出异常,堆栈也会被展开(堆栈展开),并且该进程会破坏lg哪个进程会调用unlock保证锁被释放.

  • 未来读者需要注意:RAII是C++最重要的习惯用语之一,它描述了C++和Java之间最大的意识形态差异之一.如果你从Java开始使用C++,一旦你开始利用它,你的生活将变得容易几百倍.阅读给定的链接和[这一个.](/sf/ask/162505801/) (12认同)
  • 如果OP没有看到这里真正发生的事情; `lg`是一个_local变量.`lg(m)`表达式调用`std :: lock_guard`类的构造函数,C++保证当线程退出时,将立即调用任何局部变量的析构函数.变量的范围 - 无论_how_线程退出.`lock_guard`构造函数锁定给定的锁`m`,析构函数解锁它. (9认同)
  • @BrijendarBakchodia首先,您通常不需要在堆上分配互斥锁.如果你这样做,你应该使用智能指针而不是原始的`new`或`delete`,所以你要写它`auto m = std :: make_unique <mutex>();`第二,注意[`std :: lock_guard`的构造函数](https://en.cppreference.com/w/cpp/thread/lock_guard/lock_guard)采用`std :: mutex&`.所以只需通过解除引用将该指针转换为引用:`std :: lock_guard lg(*m)` (4认同)

Rei*_*ica 29

C++的保证是什么?

与您在Java中提到的相比,C++中的相关保证的工作方式略有不同.代替的最后块,它依靠销毁自动变量对本发明范围的退出发生这种情况,因为堆栈帧被展开.无论退出范围如何,无论是优雅还是由于异常,都会发生此堆栈展开.

关于这种的场景的优选方法是使用RAII,例如通过实现std::lock_guard.它拥有一个mutex传递给其构造的对象-这里面它调用mutexlock()方法,在此之后,线程拥有互斥体-并在栈展开的范围的退出它的析构函数被调用-这里面它调用mutex"小号unlock()方法,从而释放它.

代码如下所示:

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