死锁|天天要闻

来源:哔哩哔哩 时间:2023-07-02 17:00:23

死锁(Deadlock)是指在并发系统中,两个或多个进程(线程)互相持有对方所需资源而无法继续执行的状态。这种情况下,进程将永远等待下去,直到外部干预才能解除死锁。

死锁通常涉及以下四个必要条件:

互斥条件(Mutual Exclusion):资源只能同时被一个进程占用,其他进程需要等待。


【资料图】

占有且等待(Hold and Wait):进程在等待其他资源的同时,仍然保持对已分配资源的占有。

不可抢占(No Preemption):已经分配给一个进程的资源不能被其他进程抢占,只能由持有者进程主动释放。

循环等待(Circular Wait):存在一个进程链,每个进程都在等待下一个进程所持有的资源。

Case 1 : 没有释放锁

Case 2 : 单线程重复申请锁

Case 3 : 双线程多锁申请

避免死锁的一般建议,就是让两个互斥量总以相同的顺序上锁:总在互斥量B之前锁住互斥量A,就永远不会死锁。当然前提是不同的互斥量是用于不同的地方

当有多个互斥量保护同一个类的独立实例时,如果一个操作需要对同一个类的两个不同实例进行数据交换操作,为了保证数据交换操作的正确性,需要避免数据被并发修改,并确保每个实例上的互斥量都能锁住自己要保护的区域。

然而,此时选择一个固定的顺序来上锁可能会导致问题。例如,假设选择第一个实例提供的互斥量作为第一个参数,第二个实例提供的互斥量作为第二个参数。如果有两个线程,它们都试图对相同的两个实例之间进行数据交换,但是它们接收的参数顺序不同,程序就可能会陷入死锁状态:

std::lock

std::lock可以一次性锁住多个互斥量,并且没有死锁风险。因此上述代码可以这样修改:

首先使用std::lock以相同的顺序获取两个互斥量的锁,然后使用std::adopt_lock标志将锁的所有权交给lock_guard。修改后的代码确保了以相同的顺序获取锁,从而避免了死锁的发生。无论线程以什么样的顺序进入swap函数,都能按照相同的顺序获取锁,避免了互相等待对方释放锁的情况。

std::adopt_lock

adopt_lock是一个参数,用于在构造lock_guard对象时指示它已经拥有互斥锁的所有权。当lock_guard对象被创建时,它会自动对互斥锁进行上锁,并在析构时自动解锁。而使用adopt_lock参数,它假设调用者已经拥有了互斥锁的所有权,因此在构造函数中不会尝试再次上锁。

一般情况下,使用lock_guard来管理互斥锁时,会在创建对象时自动进行上锁操作。但是,在某些情况下,例如多个互斥锁需要同时上锁时,可以先使用std::lock函数将所有的互斥锁一起加锁,然后再通过lock_guard对象管理这些已经加锁的互斥锁。这时就可以使用adopt_lock参数告诉lock_guard对象,它已经拥有互斥锁的所有权,无需再次上锁。

关键词:

推荐内容

Copyright 2000-2021 by www.jiaoyu.zuojing.com all rights reserved

备案号:豫ICP备20009784号-11

邮箱 : 85 18 07 48 3@qq.com