锁定
锁定不良:
std::mutex mtx;
void bad_lock_example() {
mtx.lock();
try
{
foo();
bar();
if (baz()) {
mtx.unlock(); // Have to unlock on each exit point.
return;
}
quux();
mtx.unlock(); // Normal unlock happens here.
}
catch(...) {
mtx.unlock(); // Must also force unlock in the presence of
throw; // exceptions and allow the exception to continue.
}
}
这是实现互斥锁定和解锁的错误方法。为确保使用 unlock()
正确释放互斥锁,需要程序员确保导致函数退出的所有流程都会导致调用 unlock()
。如上所示,这是一个脆弱的过程,因为它需要任何维护者手动继续遵循模式。
使用适当制作的类来实现 RAII,问题是微不足道的:
std::mutex mtx;
void good_lock_example() {
std::lock_guard<std::mutex> lk(mtx); // constructor locks.
// destructor unlocks. destructor call
// guaranteed by language.
foo();
bar();
if (baz()) {
return;
}
quux();
}
lock_guard
是一个非常简单的类模板,只需在其构造函数中调用其参数的 lock()
,保持对参数的引用,并在其析构函数中对参数调用 unlock()
。也就是说,当 lock_guard
超出范围时,保证 mutex
被解锁。如果它超出范围的原因是例外或提前退货并不重要 - 所有案件都得到处理; 无论控制流程如何,我们都保证能够正确解锁。