C++ 为什么我要在一个函数中锁定两个互斥锁?这也需要延迟锁定?
C++ 为什么我要在一个函数中锁定两个互斥锁?这也需要延迟锁定?,c++,std,mutex,C++,Std,Mutex,无效转账(银行账户和发件人、银行账户和收件人、整数金额) { //在没有死锁的情况下锁定两个互斥锁 std::lock(从.m到.m); //确保已锁定的两个互斥锁在作用域末尾都已解锁 std::锁紧/防护锁1(从.m开始,std::采用锁紧); std::锁紧/防护锁2(to.m,std::采用锁紧); //等效方法: //std::unique_lock lock1(from.m,std::defer_lock); //std::unique_lock 2(to.m,std::defer_l
无效转账(银行账户和发件人、银行账户和收件人、整数金额)
{
//在没有死锁的情况下锁定两个互斥锁
std::lock(从.m到.m);
//确保已锁定的两个互斥锁在作用域末尾都已解锁
std::锁紧/防护锁1(从.m开始,std::采用锁紧);
std::锁紧/防护锁2(to.m,std::采用锁紧);
//等效方法:
//std::unique_lock lock1(from.m,std::defer_lock);
//std::unique_lock 2(to.m,std::defer_lock);
//锁(锁1,锁2);
from.balance-=金额;
to.余额+=金额;
}
同时锁定两个互斥锁有什么好处?他们在这里延迟锁有什么好处
请解释他们做出这一决定的原因。
from
和to
是2
帐户,可在应用程序中的任何位置单独使用
通过为每个帐户设置互斥,您可以确保在您进行转账时,没有人使用from
或to
帐户
lock\u guard
退出功能时将释放互斥锁。如果我修改银行帐户而不锁定它,其他人可以同时尝试修改它。这是一场比赛,结果将是未定义的行为(通常丢失或神奇地创造金钱)
转账时,我修改了2个银行账户。所以它们都需要被锁定
问题是,当锁定多个东西时,每个储物柜必须以相同的顺序锁定和解锁,否则就会出现死锁
当它是银行账户时,锁没有自然的顺序。成千上万的线程可以向各个方向转移资金
因此,我们需要一种锁定多个互斥体的方法来解决这个问题,这就是std::lock
std::lock
仅锁定互斥锁-它不保证在退出当前代码块时解锁
std::lock\u guard
在销毁时解锁它所指的互斥锁(参见RAII)。这使得代码在所有情况下都能正常运行,即使出现异常,可能会导致在没有代码流过语句(如to.m.unlock()
这里有一个很好的解释(带示例):银行帐户数据结构对每个帐户都有一个锁 当把钱从一个帐户转到另一个帐户时,我们需要锁定两个帐户(因为我们从一个帐户中取出钱,然后把钱加到另一个帐户中)。我们希望此操作不会死锁,因此使用
std::lock
立即锁定这两个操作,因为这样做可以确保不会出现死锁
完成事务后,我们需要确保释放锁。这段代码使用RAII实现这一点。使用adoption\u lock
标记,我们使对象采用一个已经锁定的互斥锁(当lock1
超出范围时,将释放该互斥锁)。
使用defer\u lock
标记,我们为当前解锁的互斥锁创建一个unique\u lock
,以便稍后锁定它。同样,当唯一锁
不在范围内时,它将被解锁。的扩展
同时锁定两个互斥锁有什么好处
Richard已经很好地解释了这一点,只是解释得更明确一点:我们通过这种方式避免死锁(std::lock
的实现使得死锁不会发生)
他们在这里通过延迟锁定获得了什么
延迟锁定会导致无法立即获取它。这一点很重要,因为如果他们这样做了,他们只会在没有任何死锁保护的情况下进行操作(随后的std::lock
实现了这一点)
关于死锁避免(请参阅):
使用死锁避免算法锁定给定的可锁定对象lock1、lock2、…、lockn以避免死锁
对象被一系列未指定的锁定、尝试锁定和解锁调用锁定。[……]
旁注:另一个更简单的避免死锁的算法是始终使用e锁定银行帐户。G先降低账号(AN)。如果一个线程正在等待更高AN的锁,那么持有它的另一个线程要么已经获得了两个锁,要么正在等待第二个锁——这不能是第一个线程中的一个,因为它必须具有更高的AN
对于任意数量的线程,这并没有多大变化,任何持有较低锁的线程都在等待较高的锁(如果持有的话)。如果你画一个有向图,边从a到B,如果a正在等待B持有的第二个锁,你将得到一个(多)树结构,但你永远不会有循环子结构(这将表示死锁)。你总是可以先用更低(或更高)的帐号锁定帐户,这已经可以防止死锁。感谢您对多锁的解释。如果你能使用延迟锁来完成答案,那就太好了。谢谢。这意味着std::lock是唯一实现了死锁避免算法的锁。std::unique_lock没有避免死锁的功能?@Aquarius_Girl没有
std::unique_lock
设计为只锁定一个互斥锁-在您创建互斥锁(不延迟)或通过调用lock
告诉互斥锁(延迟)或最终尝试锁定互斥锁时锁定。同样适用于std::lock\u guard
(除了不提供延迟锁之外)。如果您将构造函数(接受一个互斥参数)与函数的参数(多个可锁定对象)进行比较,这种差异就会变得明显。@Aquarius_Girl,让我明确地提示您,在一个方面,类之间存在更基本的差异(根据RAII原理,析构函数解锁)而std::lock
是一个“仅”功能,没有解锁功能…实际上是什么
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;
}