锁定

锁定不良:

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 被解锁。如果它超出范围的原因是例外或提前退货并不重要 - 所有案件都得到处理; 无论控制流程如何,我们都保证能够正确解锁。