lock_guard与adopt_lock的隐秘细节,90%开发者都忽略了

第一章:lock_guard与adopt_lock的认知误区

在C++多线程编程中,std::lock_guard 是最常用的锁管理工具之一,用于确保互斥量在作用域内自动加锁和解锁。然而,当引入 std::adopt_lock 时,开发者常陷入对其语义的误解。

adopt_lock 的真实含义

std::adopt_lock 并不会执行加锁操作,而是假设当前线程已经持有互斥量的锁。它指示 lock_guard 在构造时不调用 lock(),仅在析构时调用 unlock()。若未预先加锁而使用该参数,行为未定义。 例如以下代码:

#include <mutex>
std::mutex mtx;

void bad_usage() {
    std::lock_guard<std::mutex> guard(mtx, std::adopt_lock); // 错误:未先 lock
}
上述调用会导致未定义行为,因为互斥量并未被当前线程锁定。

正确使用场景示例

当手动调用 lock() 后,可安全传递 adopt_lock 来交由 lock_guard 管理释放:

void safe_usage() {
    mtx.lock(); // 显式加锁
    std::lock_guard<std::mutex> guard(mtx, std::adopt_lock); // 接管锁管理
    // 临界区操作
} // 自动 unlock
此模式常见于需跨多个函数共享锁管理的情形。

常见误区归纳

  • 认为 adopt_lock 会“尝试”获取锁
  • 忽略提前加锁的必要性,直接使用 adopt_lock
  • 混淆 std::defer_lock 与 adopt_lock 的用途
标签行为
std::adopt_lock假设已加锁,仅负责解锁
std::defer_lock延迟加锁,不立即操作互斥量

第二章:adopt_lock的核心机制解析

2.1 adopt_lock的设计初衷与语义定义

在C++多线程编程中,adopt_lock 是一种用于构造锁对象的特化策略标签,其核心设计初衷在于**避免重复加锁**,并明确表达“当前线程已持有互斥量”的语义。
语义解析
adopt_lock 通常作为 std::lock_guard 或 std::unique_lock 的构造参数使用,表示该锁对象接管的是**已经由当前线程成功锁定的互斥量**。
std::mutex mtx;
mtx.lock();
std::lock_guard lock(mtx, std::adopt_lock);
上述代码中,mtx 已被显式锁定,传入 adopt_lock 告知 lock_guard 无需再次调用 lock(),仅在析构时释放锁。若省略该参数,将导致未定义行为。
典型应用场景
  • 跨函数的分阶段加锁管理
  • 条件判断后复用已获取的锁
  • 与 std::lock() 配合实现死锁避免

2.2 lock_guard配合adopt_lock的构造行为分析

adopt_lock语义解析
当使用std::adopt_lock作为std::lock_guard的构造参数时,表示调用者已持有互斥锁。此时lock_guard不会再次加锁,仅接管锁的释放责任。
  • 适用场景:跨函数传递锁状态
  • 前提条件:互斥量必须已被当前线程锁定
  • 异常安全:析构时自动解锁,避免资源泄漏
std::mutex mtx;
mtx.lock(); // 手动加锁
{
    std::lock_guard<std::mutex> lg(mtx, std::adopt_lock);
    // 此处无需加锁,直接利用已有锁状态
} // 析构时自动解锁
上述代码中,adopt_lock告知lock_guard采用“接管”模式。若省略该参数,则会重复加锁导致未定义行为。这种机制实现了锁所有权的安全转移,是复杂同步逻辑中的关键工具。

2.3 已持有锁的前提下使用adopt_lock的正确场景

理解 adopt_lock 的语义
std::adopt_lock 是一个标记类型,用于指示互斥量已由当前线程锁定。它通常作为第二个参数传递给 std::lock_guard 或 std::unique_lock 的构造函数。
  • 避免重复加锁导致未定义行为
  • 适用于跨作用域或函数间已获取锁的场景
典型使用示例
std::mutex mtx;

void inner_function(std::unique_lock& lock) {
    // 使用 adopt_lock 表示锁已持有
    std::unique_lock guard(std::move(lock), std::adopt_lock);
    // 安全执行临界区操作
}
上述代码中,adopt_lock 确保不会再次调用 lock(),而是直接接管已持有的锁状态。这在封装锁管理逻辑时尤为关键,能有效防止死锁并提升资源管理安全性。

2.4 常见误用模式及其导致的未定义行为

在并发编程中,常见的误用模式往往引发难以调试的未定义行为。最典型的是竞态条件,多个线程同时访问共享资源而未加同步。
数据竞争示例
var counter int

func increment() {
    counter++ // 非原子操作,存在数据竞争
}

func main() {
    for i := 0; i < 10; i++ {
        go increment()
    }
    time.Sleep(time.Second)
}
上述代码中,counter++ 实际包含读取、递增、写入三步操作,多个 goroutine 同时执行会导致结果不可预测。
常见误用类型归纳
  • 未使用互斥锁保护共享变量
  • 过度依赖“看似原子”的操作
  • 错误的内存可见性假设
  • 死锁:嵌套锁获取顺序不一致
正确使用 sync.Mutex 或原子操作是避免此类问题的关键。

2.5 从汇编视角看adopt_lock的运行时开销

锁语义的底层映射

std::adopt_lock 表示调用者已持有互斥量,构造函数不进行加锁操作。这一语义在汇编层面体现为函数调用的消除,避免了lock cmpxchg等原子指令的执行。

汇编指令对比分析

; std::lock_guard<mutex> lg(mtx);
mov rdi, qword ptr [mtx]
call mutex::lock()

; std::lock_guard<mutex> lg(mtx, std::adopt_lock);
; 无额外调用,仅构造栈对象
mov rax, qword ptr [rsp + 8]
mov qword ptr [lg], rax

使用adopt_lock时,编译器省略了lock()函数调用,仅执行栈变量初始化,显著减少CPU周期消耗。

性能开销对比表
模式函数调用原子操作典型时钟周期
普通lock_guard1次1次cmpxchg~30
adopt_lock00~5

第三章:实际应用中的典型用例

3.1 跨函数传递已获取的互斥锁控制权

在并发编程中,有时需要将已获取的互斥锁控制权从一个函数传递到另一个函数,以确保临界区的连续保护。
锁传递的典型场景
当多个函数共同操作共享资源时,若每个函数独立加锁,可能导致粒度失控或死锁。合理的做法是在外层函数获取锁,并将其传递给内层函数。
Go语言示例
func updateData(mu *sync.Mutex, data *int) {
    // 假设锁已在调用方获取
    *data++
}
func main() {
    var mu sync.Mutex
    var shared int
    mu.Lock()
    updateData(&mu, &shared) // 传递已加锁的互斥锁指针
    mu.Unlock()
}
代码中,main 函数获取锁后调用 updateData,后者不重新加锁,而是直接操作共享数据。这保证了跨函数执行期间的数据一致性。注意:必须确保锁的生命周期长于所有使用它的函数调用链。

3.2 在异常安全代码中维持锁状态的一致性

在多线程编程中,异常可能导致锁未被正确释放,从而引发死锁或资源泄漏。确保锁状态一致性是实现异常安全的关键环节。
RAII 与自动锁管理
通过 RAII(Resource Acquisition Is Initialization)机制,可将锁的生命周期绑定到局部对象。当异常抛出时,析构函数会自动释放锁。

std::mutex mtx;
void unsafe_operation() {
    mtx.lock();
    might_throw();  // 若抛出异常,锁无法释放
    mtx.unlock();
}
上述代码存在风险:若 might_throw() 抛出异常,unlock() 不会被调用。 使用 std::lock_guard 可解决此问题:

void safe_operation() {
    std::lock_guard<std::mutex> lock(mtx);
    might_throw();  // 异常发生时,lock 自动析构并释放锁
}
该方式利用栈对象的确定性销毁,保障异常安全下的锁一致性。
异常安全层级
  • 基本保证:异常后对象仍有效,但状态可能改变
  • 强保证:操作原子性,失败则回滚
  • 不抛异常保证:操作绝不抛出异常

3.3 避免重复加锁:adopt_lock在递归逻辑中的妙用

在递归函数中操作共享资源时,若使用普通互斥锁(如 std::mutex),可能导致同一线程重复请求锁而引发死锁。C++ 提供的 std::lock_guard 与 std::adopt_lock 结合使用,可有效规避此问题。
adopt_lock 的作用机制
std::adopt_lock 是一个标记类型,表示互斥量已被当前线程持有,构造锁对象时不重复加锁,仅在析构时释放锁。

std::mutex mtx;

void recursive_func(int depth) {
    if (depth <= 0) return;
    
    std::unique_lock lk(mtx); // 首次加锁
    // ... 操作共享资源
    
    if (depth > 1) {
        lk.unlock();                    // 手动解锁避免嵌套冲突
        recursive_func(depth - 1);
    }
}
上述代码通过手动控制锁生命周期,避免递归调用中重复竞争同一锁。更优方案是结合 std::recursive_mutex,允许同一线程多次加锁。
  • 使用 std::adopt_lock 可安全转移锁所有权
  • 适用于锁已在外部获取的场景
  • 提升递归与回调逻辑的线程安全性

第四章:与其他RAII锁管理机制的对比

4.1 adopt_lock与defer_lock在unique_lock中的差异

在C++多线程编程中,`std::unique_lock`支持多种构造策略,其中`adopt_lock`与`defer_lock`体现了不同的锁管理语义。
defer_lock:延迟加锁
使用`defer_lock`时,`unique_lock`构造时不获取互斥量,允许后续手动调用`lock()`或`try_lock()`。

std::mutex mtx;
std::unique_lock lock(mtx, std::defer_lock);
// 此时mtx未被锁定
lock.lock(); // 手动加锁
此模式适用于需要在加锁前执行准备操作的场景,避免锁的持有时间过长。
adopt_lock:已持有锁的接管
`adopt_lock`表示互斥量已被当前线程锁定,`unique_lock`仅接管其所有权,不重复加锁。

std::mutex mtx;
mtx.lock();
std::unique_lock lock(mtx, std::adopt_lock);
// mtx已被锁定,lock仅管理其释放
常用于函数返回后需延续锁生命周期的场合,确保析构时自动解锁。
策略是否立即加锁适用场景
defer_lock否延迟加锁控制
adopt_lock是(外部已锁)接管已有锁

4.2 手动解锁与adopt_lock的协同风险

在多线程编程中,手动调用 unlock() 与使用 std::adopt_lock 协同时存在潜在竞态条件。若开发者提前释放互斥量,而后续仍尝试以 adopt_lock 构造锁对象,将导致未定义行为。
典型错误场景
std::mutex mtx;
mtx.lock();
{
    std::lock_guard lg(mtx, std::adopt_lock);
    mtx.unlock(); // 错误:在 adopt_lock 前手动解锁
}
上述代码中,adopt_lock 假设互斥量已被持有,但手动调用 unlock() 破坏了这一前提,可能导致双重解锁或访问冲突。
安全实践建议
  • 避免混合使用手动解锁与RAII锁管理
  • 确保传入 adopt_lock 时互斥量确实处于锁定状态
  • 优先使用 std::lock 或 std::scoped_lock 自动化管理

4.3 条件变量等待中adopt_lock的适用边界

条件变量与锁的协作机制
在多线程同步中,条件变量通常与互斥锁配合使用。调用 wait() 时,线程必须已持有锁,随后原子性地释放锁并进入阻塞状态。
adopt_lock 的语义限制
std::adopt_lock 表示当前线程已拥有互斥量所有权,常用于 lock_guard 或 unique_lock 构造。但在条件变量的 wait() 中,该策略不被支持,因其要求自动释放与重获锁的机制,而 adopt_lock 破坏了这一过程。
std::mutex mtx;
std::unique_lock lock(mtx);
cond_var.wait(lock); // 正确:自动释放锁
// cond_var.wait(lock, std::adopt_lock); // 错误:不接受 adopt_lock
上述代码中,wait() 内部需自行管理锁的释放与获取,直接传入 adopt_lock 将导致未定义行为。因此,adopt_lock 不适用于条件变量等待场景。

4.4 移动语义下lock_guard与adopt_lock的生命期管理

在C++多线程编程中,std::lock_guard通常不支持移动语义,因其设计为栈上对象,用于作用域内自动加锁与解锁。然而,结合std::adopt_lock策略,可实现对已持有互斥量的接管。
adopt_lock的典型应用场景
当一个线程已调用mutex.lock()后,需将锁的所有权转移至lock_guard时,使用adopt_lock避免重复加锁:
std::mutex mtx;
mtx.lock(); // 手动加锁
{
    std::lock_guard guard(mtx, std::adopt_lock);
    // 此处guard仅接管锁,析构时释放
} // 自动解锁
该代码块中,adopt_lock告知lock_guard互斥量已被锁定,仅需在生命周期结束时调用unlock()。此机制确保了资源管理的安全性与RAII原则的一致性。

第五章:被忽视的细节决定系统稳定性

在高可用系统的设计中,往往决定成败的并非核心架构,而是那些容易被忽略的细节。一个看似微不足道的超时配置或资源泄漏,可能在高并发场景下引发雪崩效应。
连接池配置不当导致服务阻塞
数据库连接池若未合理设置最大连接数和等待超时,会导致请求堆积。例如,在 Go 语言中使用 sql.DB 时:

db.SetMaxOpenConns(50)
db.SetMaxIdleConns(10)
db.SetConnMaxLifetime(time.Minute)
db.SetConnMaxIdleTime(30 * time.Second)
这些参数需根据实际负载压测调整,否则连接耗尽将直接导致 HTTP 503 错误。
日志轮转缺失引发磁盘溢出
长时间运行的服务若未配置日志轮转,单个日志文件可能膨胀至数十 GB,最终占满磁盘并使服务崩溃。建议使用 logrotate 或集成支持自动切割的库,如 zap 配合 lumberjack。
健康检查路径未隔离
许多团队将健康检查(/healthz)与主业务逻辑共用数据库查询,当数据库延迟升高时,健康检查失败触发重启,加剧系统震荡。应实现轻量级独立探针:
检查项依赖资源响应时间阈值
Healthz无外部依赖<10ms
Readyz数据库连接<100ms
Livez内部协程状态<50ms
[Client] → [Load Balancer] → [Pod A (Healthz: OK)] ↓ [Database Check Timeout] → [Pod B (Readyz: Failed)]
C++11多线程之std::lock_guard和std::unique_lock C++11多线程之std::lock_guard和std::unique_lock 在C++多线程对共享数据进行修改时,我们需要加互斥锁来保护数据被正确的读和写。C++提供了std::mutex,std::mutex在同一时间,只被一个线程拿到,而其他试图lock mutex的线程会被挂起(线程挂起的状态下CPU不会分给线程时间片,那么当前挂起的线程就会暂停运行。),直到该mutex被释放后,才有可能拿到mutex并继续执行。 没有mutex的例子 #include <thread> #in 阅读详情

相关推荐

不用写代码!用AIStarter 5.0.0离线包部署InfiniteTalk的完整指南(Windows/Mac/Linux全平台)

本文详细介绍了如何使用AIStarter 5.0.0离线包在Windows、Mac和Linux平台上零代码部署InfiniteTalk数字人。从环境准备、离线资源获取与验证,到全平台部署实操指南,提供了完整的本地化安装流程和优化建议,帮助用户快速实现AI项目的一键部署。

weixin_30275415的博客 274

std::adopt_lock锁的使用

今天刚C++并发编程实战,看到一个lock_guard<std::mutex>l(mutex,std::adopt_lock);我就一直在想这个是什么东西,从字面意思理解,就是收养个锁,去msdn搜了搜,msdn是这样解释的,我也没看懂,后来看了几篇博客,大概理解了。 正文 adopt_mutex: adopt_lock确实是跟收养了个锁差不多,在test5不带参数的这个函数中,先上锁,然后托管给lock_guard这个类,这个类称为RALL(资源获取就是初始化),退出这个函数,lock_gu

dxgzg的博客 8638

科研软件|Adobe Photoshop 2024 (PS 2024)

科研软件|Adobe Photoshop 2024 (PS 2024)

m0_55499682的博客 5511

C++ 多线程std::lock_gurad和std::adopt_lock_t

首先,std::lock_gurad获取的是引用,当我们给定一个adopt_lock_t的时候,就是说我们承诺我们给的锁已经上锁了,不用二次上锁,如果不给的话,那就是给给定的锁上锁;我之前了解过lock_guard,但是看见代码中他的构造函数的时候,心想std::adopt_lock是什么东西?注意:adopt_lock_t只是一个空结构体,只是起到标记的作用,并没有什么内容上的作用;

weixin_62953519的博客 1024

医药行业新零售项目数据分析报告——基于Excel的分析与可视化

不同平台客户支付金额用数字+百分比展示更直观。各大区支付金额分析较为粗浅,后续可加入不同大区人数、配送费等进行细分分析。图表略微单一,可采用组合图,运用两个及以上维度对数据进行分析。数据来源本项目数据来源于某机构的项目案例,以上分析内容均为本人原创,不涉嫌抄袭。原做项目,新平台首发。

2401_84213513的博客 1495

【电子元件篇】MOSFET场效应管作用、选型和测量指南-超简单解读

场效应管是一种电压控制型半导体器件,相比三极管具有输入阻抗高、噪声小、功耗低等优势。主要分为结型和绝缘栅型两大类,后者又可分为耗尽型和增强型MOS管。场效应管通过栅极电压控制漏极电流,具有转移特性和输出特性两大静态特性,以及快速的开关特性。其关键参数包括饱和漏源电流、夹断电压、跨导等,应用场景涵盖信号放大、恒流源、阻抗变换等领域。使用时需根据电路需求选择合适类型,如结型管适合一般放大,功率MOSFET适合高压大电流场合。检测时可用万用表电阻档初步判断好坏和放大能力。

2301_81299416的博客 2540

adopt_lock 和 defer_lock 的区别

下面三种方法在同时锁住多个互斥量时,是等价的先同时 lock,再创建 guard先创建 guard, 再同时 lock使用 scoped_lockTypeEffect(s)

... 2998

点云直线检测-3DLineDetection复现

点云直线分割-Fast 3D line detection

阁楼 8156

【C++11并发与多线程笔记(4)】

C++11并发与多线程笔记(4)unique_lock详解unique_lock取代lock_guardunique_lock的第二个参数std::adopt_lockstd::try_to_lockstd::defer_lockunique_lock的成员函数lock()unlocktry_lockrelease()unique_lock所有权的传递 unique_lock详解 unique_lock取代lock_guard unique_lock的第二个参数 std::adopt_lock std::t

qq_41855185的博客 1525

CentOS7.9 安装 ImageMagick,图片转换为HEIC图像格式

由于ImageMagick7以下不支持heic等图片格式,所以重新安装了ImageMagick7.1版本支持heic格式,在网上找了很多资料,归纳总结并写此文章记录一下。在Linux(CentOS7.9)上安装ImageMagick7.1.1-38。

shmily_i的博客 1940

用 Joule 点燃 ABAP 开发者的舞台感:SAP BTP 上的 ABAP AI 能力实战解读

摘要:SAP推出的Joule for developers和ABAP AI功能为开发者提供了智能辅助工具,旨在优化ABAP开发流程。主要功能包括上下文感知的代码预测补全、代码解释、单元测试生成和开发问题实时解答。这些能力特别适合应对Cloud环境下ABAP开发的复杂约束,如Clean Core原则和受限语法范围。通过减少重复劳动和提升代码理解效率,该工具帮助开发者将注意力集中在业务逻辑而非技术细节上。随着企业加速向S/4HANA迁移,这些AI功能将在遗留代码改造和云适配中发挥更大作用,建议团队将其纳入工程体

2007 年 ~ 2025 年,深耕 SAP 技术 18 年 298

多线程共享数据的保护+互斥量概念、用法、死锁演示及解决详解(std::lock()、std::adopt_lock)

#include <list> #include <thread> class A { public: //把收到的消息(玩家命令)入到一个队列的线程 void inMsgRecvQueue() { for (int i = 0;i < 100000;++i) { cout << "inMsgRecvQueue()执行,插入一个元素" << i << endl;

HITXJ的博客 1275

计算机网络基础:揭开网络世界的神秘面纱

计算机网络基础:揭开网络世界的神秘面纱,计算机网络已深度融入现代生活,这篇文章对其基础内容展开全面阐述。开篇介绍计算机网络的定义,说明其由计算机设备、网络设备和传输介质构成。接着从地域范围和拓扑结构两个维度对计算机网络进行分类,并详细讲解 OSI 和 TCP/IP 参考模型,明晰各层功能与联系。随后阐述网络通信协议的定义及常见协议,如 TCP/IP、HTTP 等。最后聚焦网络安全,涵盖定义、重要性以及防火墙、加密技术等常用安全技术。文章旨在帮助读者构建计算机网络基础知识体系,理解其在生活和工作中的应用与价值

不踩坑,不知道坑有多深;不总结,踩过的坑白踩。 6万+

C++线程编程-互斥锁的死锁与死锁防止

产生死锁的原因: 存在多个互斥锁,并且多线程之间竞争互斥锁 多线程之间相互等待 死锁避免: 如果有多个互斥锁,可以使用lock将多把锁一起锁起来,并用lock_guard封装,自动释放锁 如果确实需要分开锁,应确保上锁的顺序和解锁的顺序相反 使用层级锁 如果一个线程等待你,你就不要再等待它 lock_guard<> 没有任何功能,只是将互斥锁封装,在离开作用的时候自动析构,释放锁。 不支持复制,不支持移动 unique_lock<> 支持上锁解锁功能,可以移动但不支持复制。

NINE_world的博客 839

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

C++ 并发指南 std::lock

C++11 标准为我们提供了两种基本的锁类型,分别如下: std::lock_guard,与 Mutex RAII 相关,方便线程对互斥量上锁。 std::unique_lock,与 Mutex RAII 相关,方便线程对互斥量上锁,但提供了更好的上锁和解锁控制。 另外还提供了几个与锁类型相关的 Tag 类,分别如下: std::adopt_lock_t,一个空的标记类,定义如下: struct adopt_lock_t {}; 该类型的常量对象adopt_lock。 adopt_lock 是一个

qq_24649627的博客 1856

IMSL CNL 7.0.0 (x86-64)Crack

IMSL CNL 7.0.0 (x86-64)Crack intel的算法库破解文件,这是C++版本的破解文件

C++多线程(二)---- mutex互斥量、lock_guard<mutex>、unique_lock<mutex>的使用和各种方式加锁的区别(详细解析~~~)

C++多线程(二)---- 多线程资源竞争、std::mutex互斥量、lock_guard、unique_lock的使用和各种方式加锁的区别(详细解析~~~)

weixin_43978744的博客 5136

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

C++并发与多线程(二)互斥量与死锁

互斥量与死锁 互斥量的基本概念 互斥量是个类对象,其头文件是<mutex> 互斥量可以理解成一把锁,可以调用其成员函数lock() 与unlock() 来为线程加锁和开锁 多个线程尝试用lock() 成员函数来为锁头加锁,只有一个线程能锁定成功,没有成功则继续卡在lock() 这里继续尝试加锁,当先前加锁成功的线程运行结束后利用unlock() 解锁,其他的线程才能加锁成功,继续运行。 当两个线程对共享内容进行读写操作时,可以给这两个线程加锁,从而保证同一时间只有一个线程可以对共享内容进行操

qq_41578079的博客 938

c++11 std::defer_lock, std::try_to_lock, std::adopt_lock

std::adopt_lock Value used as possible argument to the constructor of unique_lock or lock_guard. unique_lock objects constructed with adopt_lock do not lock the mutex object on construction, assuming instead that it is already locked by the current thread

李白 3368

C++多线程加锁详解(易于理解)

参考:C++多线程基础教程 c++11多线程之使用std::try_to_lock摸鱼 #include mutex m; // 实例化对象m m.lock(); // 不推荐这么做,如果忘记unlock会锁死。 m.unlock(); // 使用lock_guard or unique_lock避免该问题 lock_guard gl(m,参数); // 出了{}作用域自动解锁。(参数可以为空自动锁) unique_lock gl(m,参数); lock_guard unique_lock

编程改变世界。想做一些改变世界的产品。感谢一键三连。 5243

3 —— 多线程的同步和异步

一 创建多个线程 #include <iostream> #include <thread> #include <vector> using namespace std; // 线程入口函数 void myprint(int num) { cout << this_thread::get_id() << "thread star...

baboon_chen 1991

52 C++ unique_lock 替代 lock_guard 详解

返回它所管理的mutex对象指针,并释放所有权,也就是说:这个uique_lock 和mutex不在有关系,如果这时候mutex处理加锁状态,则要程序员自己对这个mutex进行unlock操作。我们会尝试用mutex的lock()去锁定这个mutex,但是如果没有锁定成功,我也会立即返回,并不会阻塞在这里。好处是不用管unlock(),在 sbguard1的析构函数调用的时候,会调用 mymutex1的析构函数。之前的lock_guard是要在析构函数调用的时候,才会调用 mutex.unlock();

hunandede的博客 1236

C++温故补缺(十八):lock类

defer_lock是暂时先不加锁,和未上锁的状态是一致的,而adopt_lock假设线程已经获取了锁,在mutex对象中,有个m_owns参数,也就是前面说的ownership,被谁获取了,这个值表示是否被调用的线程获取mutex对象的所有资源。但是并不是上锁的意思,上锁的参数是mutex对象的数据域的_lock值控制的,defer_lock和未上锁的状态一致,m_owns为false,data域的_lock值为0。当使用lock()手动上锁时,m_owns为true,data域的_lock值为1。

Chocolate的博客 319

C++11 defer_lock try_to_lock adopt_lock

一 类型 1. std::defer_lock_t 、 std::try_to_lock_t 和 std::adopt_lock_t 是用于为 std::lock_guard(C++11) 、 std::scoped_lock(C++14) 、 std::unique_lock(C++11) 和 std::shared_lock(C++17) 指定锁定策略的空结构体标签类型。 2. std::defer_lock 、 std::try_to_lock 和 std::adopt_lock 分别是 std::

程序员Link 1218

C++日记——Day40:互斥量概念、用法、死锁演示及解决详解、std::lock()模板、std::lock_guard的std::adopt_lock参数

互斥量基本概念 保护共享数据,某个线程 用代码把共享数据锁住,其它想操作共享数据线程必须等待解锁 基本过程:锁定,操作,解锁 互斥量:是个类对象。理解成一把锁,多个线程尝试用lock()函数来加锁这把锁头时,只有一个线程能锁定成功。(成功的标志是lock()函数返回),如果没锁成功,那么流程卡在lock()这里不断尝试去锁这把锁头。 慎用lock()保护共享数据不多也不少,少了达不到效果,...

weixin_38278993的博客 636

C++标准库冷知识:adopt_lock为何被严重低估?

掌握C++多线程编程技巧,解析C++ lock_guard 的 adopt_lock 用法。适用于已加锁场景,避免重复加锁,提升性能与安全性。深入讲解其原理与最佳实践,值得收藏。

FuncLens的博客 312

C++11 多线程(中)

lock()内的两个互斥量,对顺序没有要求。unique_guard()可以取代lock_gaurd(),unique_guard()可能会占用更多的内存,但是unique_guard()的使用会比lock_guard()更灵活,上面我么说到过lock_guard()的第二个参数adopt_lock,当然unique_guard()也支持这个参数,和lock_guard()的作用是一样的,下面我们就来看看unique_guard()的不同的第二个参数。

qq_66157971的博客 353
上一篇: 【C++虚析构函数深度解析】:为何纯虚析构函数必须定义?揭秘背后原理
下一篇: 【C++20高级特性精讲】:<=>运算符返回类型如何影响类设计?
ProcePerch
博客等级 码龄1年 150粉丝 1977原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符  | 博主筛选后可见
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值