首页
学习
活动
专区
工具
TVP
发布
精选内容/技术社群/优惠产品,尽在小程序
立即前往

为什么` `std::lock`不使用全局排序锁定互斥锁?

std::lock是C++标准库中的一个函数,用于同时锁定多个互斥锁,以避免死锁和提高并发性能。它的设计目的是为了解决多个互斥锁的死锁问题。

在实现上,std::lock函数使用了一种叫做"锁的层级化"的技术,而不是全局排序锁定互斥锁。全局排序锁定互斥锁是一种简单的方法,它要求所有线程按照某种全局顺序来获取互斥锁,以避免死锁。然而,这种方法存在一些问题。

首先,全局排序锁定互斥锁会引入额外的开销。因为所有线程都必须按照全局顺序来获取互斥锁,这就需要维护一个全局的锁定顺序,而且每次获取互斥锁都需要检查这个顺序。这会增加锁的竞争和系统开销。

其次,全局排序锁定互斥锁会限制并发性能。因为所有线程都必须按照全局顺序来获取互斥锁,这就导致了所有线程之间的串行化。如果一个线程在获取互斥锁时被阻塞,那么其他线程也必须等待,即使它们之间没有竞争关系。这会降低系统的并发性能。

相比之下,std::lock函数使用了一种更高效的层级化锁定策略。它会根据互斥锁的地址来确定锁的层级关系,并按照层级顺序来获取互斥锁。这样可以避免全局排序锁定互斥锁的开销和并发性能问题。

总结起来,std::lock不使用全局排序锁定互斥锁的原因是为了避免额外的开销和限制并发性能。它采用了一种更高效的层级化锁定策略,以解决多个互斥锁的死锁问题。

页面内容是否对你有帮助?
有帮助
没帮助

相关·内容

来聊聊C++中头疼的线程、并发

其中std::mutex表示普通互斥锁,可以与std::unique_lock配合使用,把std::mutex放到unique_lock中时,mutex会自动上锁,unique_lock析构时,同时把mutex...常用的成员函数有: 构造函数:std::mutex不支持copy和move操作,最初的mutex对象处于unlocked状态。 lock函数:互斥锁被锁定。...std::try_to_lock 表示我们会尝试用mutex的lock去锁定这个mutex,如果没有锁定成功,就立即返回,并不会阻塞在哪里。...unlock() try_lock() 尝试给互斥量加锁,不阻塞。...当多个线程访问同一共享资源时,不但需要用互斥锁实现独享访问以避免并发错误(竞争危害),在获得互斥锁进入临界区后还需要检验特定条件是否成立: 若不满足该条件,拥有互斥锁的线程应该释放该互斥锁,使用unique_lock

5.1K41
  • 线程同步与互斥

    无锁编程 不是什么时候都要靠上锁的。从根源出发,我们为什么需要上锁?因为线程在使用资源的过程中可能会出现冲突,对于这种会出现冲突的资源,还是锁住轮着用比较好。...3️⃣重试代价:如果重试代价大,建议采用悲观锁。悲观锁依赖数据库锁,效率低。更新失败的概率比较低。 自旋锁 互斥锁:阻塞等待,wait() 自旋锁:等两下就去问一声:好了不?我很急啊!好了不?...unique_lock是一个通用的互斥量锁定包装器,它允许延迟锁定,限时深度锁定,递归锁定,锁定所有权的转移以及与条件变量一起使用。...特点如下: 创建时可以不锁定(通过指定第二个参数为std::defer_lock),而在需要时再锁定 可以随时加锁解锁 作用域规则同 lock_grard,析构时自动释放锁 不可复制,可移动 条件变量需要该类型的锁作为参数...但是互斥锁一个明显的缺点是它只有两种状态:锁定和非锁定。

    83310

    C++ std::unique_lock 用法

    你可以在构造函数中传入一个互斥锁(std::mutex 或其它互斥锁类型)来创建 std::unique_lock 对象,并且会在构造时获取互斥锁的所有权。...3.延迟加锁与手动加解锁 std::unique_lock 还支持在初始化时不立即加锁,而是在需要时延迟加锁。...: lock.lock(); // 手动加锁 // 临界区代码 lock.unlock(); // 手动解锁 你可以使用 lock() 手动加锁,然后在互斥锁保护的临界区内执行代码,最后使用 unlock...请注意,返回前调用 lck.lock() 加锁可能会再次阻塞线程。 为什么条件变量需要互斥锁的配合呢? 因为 condition 和等待队列都是多线程的共享资源,当访问这些共享资源时需要互斥访问。...在多数情况下,推荐使用 std::unique_lock 而不是直接操作互斥锁,因为它能够自动管理锁的生命周期,减少了出错的机会。

    1.7K21

    C++17中的std::scoped_lock:简化多锁管理的利器

    为什么需要std::scoped_lock在多线程环境中,当多个线程需要访问共享资源时,通常会使用锁(如std::mutex)来防止数据竞争。...它的主要作用是自动管理多个互斥锁的生命周期,确保这些锁在作用域结束时被正确释放。2.1 基本语法std::scoped_lock的构造函数接受一个或多个互斥锁对象作为参数,并在构造时自动锁定这些锁。...它会按照某种固定的顺序(通常是锁的地址顺序)来锁定互斥锁,这样即使多个线程同时使用std::scoped_lock管理相同的锁,也不会出现死锁。...3.2 简化代码使用std::scoped_lock可以显著减少锁管理相关的代码量。开发者无需手动锁定和解锁多个锁,只需将锁对象传递给std::scoped_lock即可。...std::scoped_lock可以用来同时锁定连接池的互斥锁和连接的互斥锁,确保操作的线程安全性。

    12800

    线程同步-The Boost C++ Libraries

    这将导致线程等待,直到拥有互斥锁的线程完成处理并释放其对该互斥锁的所有权为止。 示例44.7使用类型为boost::mutex的全局互斥锁,称为互斥锁。...两种变体仍然在循环中向标准输出流写入五个数字,但是现在它们使用类boost::unique_lock来锁定互斥体。...thread1()将变量互斥锁传递给boost::unique_lock的构造函数,这使boost::unique_lock尝试锁定互斥锁。...这使得boost::unique_lock的构造函数不调用互斥锁上的lock(),而是调用try_lock()。因此,构造函数仅尝试锁定互斥锁。如果互斥锁由另一个线程拥有,则尝试失败。...owns_lock()可让您检测boost::unique_lock是否能够锁定互斥锁。如果owns_lock()返回true,thread2()可以立即访问std::cout。

    85210

    并发编程(从C++11到C++17)

    所以这些类都提供了下面三个方法,并且它们的功能是一样的: 方法 说明 lock 锁定互斥体,如果不可用,则阻塞 try_lock 尝试锁定互斥体,如果不可用,直接返回 unlock 解锁互斥体 这三个方法提供了基础的锁定和解除锁定的功能...,不获得互斥的所有权 try_to_lock C++11 类型为try_to_lock_t,尝试获得互斥的所有权而不阻塞 adopt_lock C++11 类型为adopt_lock_t,假设调用方已拥有互斥的所有权...<< '\n'; } 这段代码中: 1.全局的互斥体g_i_mutex用来保护全局变量g_i2.这是一个设计为可以被多线程环境使用的方法。...因此需要通过互斥体来进行保护。这里没有调用lock方法,而是直接使用lock_guard来锁定互斥体。...3.在方法结束的时候,局部变量std::lock_guardstd::mutex> lock会被销毁,它对互斥体的锁定也就解除了。4.在多个线程中使用这个方法。

    936130

    多线程

    ,在不同线程访问同一个资源的时候,会发生不一致的情况,为了数据的同步,必须使用锁 锁的种类 按照锁的种类分类,可以分为以下几种 互斥锁 自旋锁 条件变量 1....对于互斥锁在C++标准库里有的: std::mutex,可以阻塞式等锁(lock())也可以非阻塞式上锁(try_lock()),lock可以同时锁定几个互斥量,try_lock如果锁定失败会直接返回...,递归互斥锁,在互斥锁的基础上允许持有锁的线程多次通过lock()或者try_lock()获取锁,而std::mutex的拥有者不能继续请求上锁 std::recursive_timed_mutex...,递归互斥锁加时版 std::shared_mutex,共享互斥锁,允许多个线程共享锁(lock_shared()系列),但只有一个线程能够持有互斥锁(lock()系列),也就是一般所说的读写锁...(提前)解锁 std::shared_lock,配合共享锁使用的锁管理器 再深入了解读写锁 在c++里实现读写锁 #include //std::unique_lock #

    60220

    C++17中的shared_mutex与C++14的shared_timed_mutex

    独占性 --- 仅一个线程能占有互斥。其对应的就是写的访问权限。 若一个线程已获取独占性锁(通过 lock、try_lock),则无其他线程能获取该锁(包括共享的)。...仅当任何线程均未获取独占性锁时,共享锁能被多个线程获取(通过 lock_shared、 try_lock_shared)。在一个线程内,同一时刻只能获取一个锁(共享或独占性)。...shared_mutex提供了排他性锁定方法有: 函数 功能描述 备注 lock 锁定互斥,若互斥不可用则阻塞 公有成员函数 try_lock 尝试锁定互斥,若互斥不可用则返回 公有成员函数 unlock...解锁互斥 公有成员函数 注:通常不直接调用 lock() 和unlock(),而是用 std::unique_lock 与 std::lock_guard管理排他性锁定。...解锁互斥 公有成员函数 注:通常不直接调用 lock() 和unlock(),而是用 std::unique_lock 与 std::lock_guard管理排他性锁定。

    1.3K21

    硬核!C++并发编程(C++11到C++17)

    一旦某个线程获取了互斥锁,任何其他线程都无法再获取互斥锁和共享锁;但是如果有某个线程获取到了共享锁,其他线程无法再获取到互斥锁,但是还有获取到共享锁。这里互斥锁的使用和其他的互斥体接口和功能一样。...通用锁定算法 主要API 要避免死锁,需要仔细的思考和设计业务逻辑。 有一个比较简单的原则可以避免死锁,即:对所有的锁进行排序,每次一定要按照顺序来获取锁,不允许乱序。...<< '\n'; } 这段代码中: 全局的互斥体g_i_mutex用来保护全局变量g_i 这是一个设计为可以被多线程环境使用的方法。...因此需要通过互斥体来进行保护。这里没有调用lock方法,而是直接使用lock_guard来锁定互斥体。...在方法结束的时候,局部变量std::lock_guardstd::mutex> lock会被销毁,它对互斥体的锁定也就解除了。 在多个线程中使用这个方法。

    1.4K40

    Linux:多线程(二.理解pthread_t、线程互斥与同步、基于阻塞队列的生产消费模型)

    初始化: 定义的锁是静态或者全局的,使用静态分配。...销毁互斥量: 销毁互斥锁是在不再需要使用互斥锁时释放其资源的重要操作。...申请锁成功:函数就会返回,允许你继续向后运行 申请锁失败:函数就会阻塞,不允许你继续向后运行 函数调用失败:出错返回 当调用 pthread_mutex_lock 函数时,如果互斥量处于未锁定状态,那么该函数会成功将互斥量锁定...然而,如果在调用 pthread_mutex_lock 函数时,其他线程已经锁定了互斥量,或者有其他线程同时尝试锁定互斥量但未竞争成功,那么当前线程的调用将会被阻塞(即执行流被挂起),直到互斥量被解锁为止...常见可重入的情况 使用函数内数据:函数内部使用的所有数据都是函数本地的局部变量,不涉及全局变量或静态变量。

    73310

    C++中线程同步与互斥的4种方式介绍、对比、场景举例

    锁(Lock)除了直接使用互斥量,C++还提供了std::lock_guard和std::unique_lock两种锁,用于自动管理互斥量的所有权。...std::unique_lockstd::mutex> lock(mtx); // 创建锁,自动获取互斥量的所有权...对比策略优点缺点单一全局互斥量简单可能导致严重的性能问题,降低并发性多个互斥量提高并发性增加程序复杂性,需要避免死锁原子操作提高并发性,避免互斥量开销增加程序复杂性,需要理解和使用原子操作读写锁提高并发性...在这种情况下,我们可以使用多个互斥量的策略。我们可以将用户对象划分为几个组,每个组有一个关联的互斥量。当一个线程需要访问一个用户对象时,它只需要锁定该用户对象所在组的互斥量,而不是所有的用户对象。...以下是一个使用原子操作和锁的例子:#include #include #include std::mutex mtx; // 全局互斥量std::atomic

    28500

    C++中锁和互斥量的原理、区别和使用建议

    std::mutex mtx;mtx.lock();// 访问共享资源mtx.unlock();锁(Lock)锁是一种更高级的同步机制,它是建立在互斥量之上的。...锁提供了一种自动管理互斥量的方式,使得在发生异常时能够自动释放互斥量,防止死锁。在C++中,锁由std::lock_guard和std::unique_lock两个类表示。...灵活性:std::unique_lock比std::lock_guard更灵活,它允许延迟锁定、尝试锁定和可转移锁所有权。示例下面是一个使用互斥量和锁的例子,它演示了如何在多线程环境中保护共享资源。...而锁则可以保证在任何情况下都能正确释放互斥量。自动管理:使用锁可以自动管理互斥量的生命周期,无需手动调用lock()和unlock()方法,使代码更简洁,也更容易避免错误。...灵活性:std::unique_lock比std::lock_guard更灵活,它允许延迟锁定、尝试锁定和可转移锁所有权。然而,这并不是说我们完全不需要直接使用互斥量。

    8200

    46.python GIL锁与互斥锁Lock的区别

    一.python线程互斥锁Lock python中,当有多个线程threading同时执行时,对同一个全局变量或者同一个文件操作时,如果没有设置互斥锁,容易造成数据混乱,比如下面这两个案例: 1.案例一...注意:互斥锁一旦锁定之后要记得解锁,否则资源会一直处于锁定状态,容易造成死锁; ?...假设Thread1获得GIL可以使用cpu,这时Thread1获得 互斥锁lock,Thread1可以改date数据(但并没有开始修改数据); (2)Thread1线程在修改date数据前发生了 i/o...lock,所以Thread2无法更改共享数据date,这时Thread2让出Gil锁 , GIL锁再次发生竞争; (5)假设Thread1又抢到GIL,由于其有互斥锁Lock所以其可以继续修改共享数据data...,当Thread1修改完数据释放互斥锁lock,Thread2在获得GIL与lock后才可对data进行修改; 以上描述了 互斥锁和Gil锁的 一个关系 猜你喜欢: 1.python线程threading

    1.8K31

    C++ 多线程 —— 锁

    任何是一个线程都要使用互斥锁互斥访问任务队列,以避免多个线程同时访问任务队列以发生错乱。 在某一时刻,只有一个线程可以获取互斥锁,在释放互斥锁之前其他线程都不能获取该互斥锁。...C++ 语法 项目 内容 头文件 类型 std::mutex 用法 在C中,通过构造 std::mutex 的实例创建互斥元,调用成员函数 lock() 来锁定它,调用 unlock...() 来解锁不过一般不推荐这种做法,标准C库提供了 std::lock_guard 和 unique_lock 类模板,都是 RAII 风格,它们是在定义时获得锁,在析构时释放锁。...它们的主要区别在于 unique_lock 锁机制更加灵活,可以再需要的时候进行 lock 或者 unlock 调用,不非得是析构或者构造时。...假设线程T1获取互斥锁并且正在core1上运行时,此时线程T2也想要获取互斥锁(pthread_mutex_lock),但是由于T1正在使用互斥锁使得T2被阻塞。

    1.4K60

    C++锁:概念、不同锁实现、死锁现象+代码实例+预防+避免、加锁性能降低8种有效策略(万字长文)

    ) 多线程可并发读取,但写操作独占 提高读操作多的场景下的并发性能 写操作需要独占锁,读多写少时性能最佳 数据读多写少的场景 自旋锁 (std::atomic_flag) 线程忙等待,不阻塞,适合短期锁...以下是互斥锁的工作流程: 在这个流程图中: 线程开始时,它会检查锁的状态。 如果锁未被锁定,线程会获取锁,然后访问资源。访问完成后,线程会释放锁,然后结束。 如果锁已被锁定,线程会等待锁被释放。...这种锁适用于锁持有时间短且线程不希望在重新调度上花费过多时间的情况。 以下是自旋锁的工作流程: 在这个流程图中: 线程开始时,它会检查锁的状态。 如果锁未被锁定,线程会获取锁,然后访问资源。...实现:在多锁操作时使用 std::lock,保证同时锁定多个资源。...实现:使用 std::atomic 或无锁数据结构替代互斥锁。

    27910

    C++锁(万字长文):概念、不同锁实现、死锁现象+代码实例+预防+避免、加锁性能降低8种有效策略

    写操作需要独占锁,读多写少时性能最佳 数据读多写少的场景 自旋锁 (std::atomic_flag) 线程忙等待,不阻塞,...如果锁未被锁定,线程会获取锁,然后访问资源。访问完成后,线程会释放锁,然后结束。如果锁已被锁定,线程会等待锁被释放。当锁被释放后,线程会再次检查锁的状态,然后重复上述过程。这就是互斥锁的基本工作流程。...这种锁适用于锁持有时间短且线程不希望在重新调度上花费过多时间的情况。以下是自旋锁的工作流程:在这个流程图中:线程开始时,它会检查锁的状态。如果锁未被锁定,线程会获取锁,然后访问资源。...实现:在多锁操作时使用 std::lock,保证同时锁定多个资源。...实现:使用 std::atomic 或无锁数据结构替代互斥锁。3.4 如何处理已发生的死锁死锁检测与恢复在程序设计中引入死锁检测机制,当检测到死锁时,采取恢复策略(如强制释放资源或终止某些线程)。

    87922

    【Linux】线程ID与互斥、同步(锁、条件变量)

    锁 pthread_mutex_t是互斥锁类型。 互斥锁在任何时刻,只允许一个线程进行资源访问。...有了锁,我们往往需要初始化和销毁锁,初始化有两种做法: 如果定义的是全局或者静态的锁,可以只使用pthread_mutex_t 锁的名字 =PTHREAD_MUTEX_INITIALIZER 如果定义的这把锁是动态申请的...lock的情况: 互斥量处于未锁状态,该函数会将互斥量锁定,同时返回成功 发起函数调用时,其他线程已经锁定互斥量,或者存在其他线程同时申请互斥量,但没有竞争到互斥量, 那么pthread_ lock...最后再把线程函数代码换成抢票的代码即可,结果跟用全局的一样。 因此锁的使用既可以用全局的,也可以以参数的形式传递给线程。...它的使用跟前面互斥锁一样,可以定义成局部或者全局的。如果是全局或者静态的,可以直接使用 PTHREAD_COND_INITIALIZER 初始化。

    11210

    CC++ Qt QThread 线程组件应用

    ::cout " std::endl; return a.exec(); } QMutex 互斥同步线程锁: QMutex类是基于互斥量的线程同步锁...,该锁lock()锁定与unlock()解锁必须配对使用,线程锁保证线程间的互斥,利用线程锁能够保证临界资源的安全性....QMutexLocker会保护加锁区域,并自动实现互斥量的锁定和解锁操作,可以将其理解为是智能版的QMutex锁,该锁只需要在上方代码中稍加修改即可....() std::endl; msleep(900); } } }; 互斥锁存在一个问题,每次只能有一个线程获得互斥量的权限,如果在程序中有多个线程来同时读取某个变量...,那么使用互斥量必须排队,效率上会大打折扣,基于QReadWriteLock读写模式进行代码段锁定,即可解决互斥锁存在的问题.

    29410
    领券