为什么我要在一个函数中锁定两个互斥锁 - 这也是延迟锁定?

Aqu*_*irl 0 c++ mutex std

https://en.cppreference.com/w/cpp/thread/lock_tag

void transfer(bank_account &from, bank_account &to, int amount)
{
    // lock both mutexes without deadlock
    std::lock(from.m, to.m);
    // make sure both already-locked mutexes are unlocked at the end of scope
    std::lock_guard<std::mutex> lock1(from.m, std::adopt_lock);
    std::lock_guard<std::mutex> lock2(to.m, std::adopt_lock);

// equivalent approach:
//    std::unique_lock<std::mutex> lock1(from.m, std::defer_lock);
//    std::unique_lock<std::mutex> lock2(to.m, std::defer_lock);
//    std::lock(lock1, lock2);

    from.balance -= amount;
    to.balance += amount;
}
Run Code Online (Sandbox Code Playgroud)

通过一次锁定两个互斥锁可以获得什么?
他们在这里得到了什么?

请解释他们的决定背后的原因.

Ric*_*ges 7

如果我修改银行帐户而不锁定它,其他人可能会尝试同时修改它.这是一场比赛,结果将是未定义的行为(通常是丢失或神奇创造的钱).

在转账时,我正在修改2个银行账户.所以他们都需要被锁定.

问题是当锁定多个东西时,每个锁定器必须以相同的顺序锁定和解锁,否则我们会遇到死锁.

当它是银行账户时,没有自然的锁定顺序.成千上万的线程可以向各个方向转移资金.

所以我们需要一种方法来锁定多个互斥锁,以此方式解决这个问题 std::lock

std::lock 仅锁定互斥锁 - 它不保证在退出当前代码块时解锁.

std::lock_guard<>解锁它在破坏时所指的互斥锁(参见RAII).这使得代码在所有情况下都能正常运行 - 即使存在可能导致提前退出当前代码块的异常,而不会使代码流过语句,例如to.m.unlock()

这里有一个很好的解释(带例子):https://wiki.sei.cmu.edu/confluence/display/cplusplus/CON53-CPP.+Avoid+deadlock+by+locking+in+a+predefined+order