错误锁定:
std::mutex mtx; void bad_lock_example() { mtx.lock(); try { foo(); bar(); if (baz()) { mtx.unlock(); // 必须在每个出口点解锁。 return; } quux(); mtx.unlock(); // 正常解锁发生在这里。 } catch(...) { mtx.unlock(); // 还必须在以下情况下强制解锁 throw; // 例外,并允许例外继续。 } }
这是实现互斥锁的锁定和解锁的错误方法。为确保正确释放互斥量,unlock()要求程序员确保导致函数退出的所有流程都导致对的调用unlock()。如上所示,这是一个脆弱的过程,因为它要求任何维护人员继续手动遵循该模式。
使用适当设计的类来实现RAII时,这个问题很简单:
std::mutex mtx; void good_lock_example() { std::lock_guard<std::mutex> lk(mtx); // 构造函数锁。 //析构函数解锁。析构函数调用 // 由语言保证。 foo(); bar(); if (baz()) { return; } quux(); }
lock_guard是一个非常简单的类模板,它仅lock()在其构造函数中调用其参数,保留对该参数的引用,并unlock()在其析构函数中调用该参数。也就是说,当lock_guard超出范围时,mutex可以确保将其解锁。超出范围的原因是异常还是提前返回都无所谓-所有案例都已处理;无论控制流程如何,我们都保证可以正确解锁。