C++ 锁定

示例

错误锁定:

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可以确保将其解锁。超出范围的原因是异常还是提前返回都无所谓-所有案例都已处理;无论控制流程如何,我们都保证可以正确解锁。