0

0

c++如何使用mutex互斥锁_c++线程安全控制【实战】

冰火之心

冰火之心

发布时间:2026-02-09 11:43:15

|

576人浏览过

|

来源于php中文网

原创

std::mutex必须配合RAII锁管理器使用,推荐std::lock_guard或C++17的std::scoped_lock;禁止裸调用lock/unlock,须确保加锁顺序一致以防死锁,且mutex不可跨线程释放。

c++如何使用mutex互斥锁_c++线程安全控制【实战】

std::mutex 必须配合 std::lock_guard 或 std::unique_lock 使用

直接调用 mutex.lock()mutex.unlock() 极易出错:忘记 unlock、异常中途跳出、提前 return 都会导致死锁。C++ 标准库不鼓励裸调用,而是依赖 RAII 自动管理生命周期。

正确做法是把 std::mutexstd::lock_guard(最常用)或 std::unique_lock(需延迟加锁/转移所有权时用)配对:

std::mutex mtx;
int shared_data = 0;

void increment() {
    std::lock_guard lock(mtx); // 构造即加锁
    ++shared_data;                          // 临界区
} // 析构自动 unlock —— 即使抛异常也安全
  • std::lock_guard 轻量、不可复制、不可转移,适合“一进一出”简单场景
  • std::unique_lock 更灵活(支持 try_lock()defer_lockrelease()),但有轻微开销
  • 切勿在多个函数间传递 std::lock_guard 对象,它不是锁本身,只是锁的 RAII 封装

多个 mutex 加锁顺序不一致会引发死锁

当多个线程需要同时操作两个共享资源(比如账户 A 和 B 的余额),若各自按不同顺序加锁(线程1先锁 A 再锁 B,线程2先锁 B 再锁 A),就可能互相等待,形成死锁。

解决方法只有一条铁律:所有线程必须以**全局一致的顺序**获取多个 mutex。常见策略:

立即学习C++免费学习笔记(深入)”;

  • 按 mutex 对象地址排序:std::scoped_lock(C++17 起)自动按地址升序加锁,推荐优先使用
  • 手动约定顺序,比如始终按变量声明顺序或 ID 数值大小加锁
  • 避免在持有 mutex 期间调用可能再申请其他 mutex 的第三方函数(尤其是非内联、无文档说明线程安全性的函数)
std::mutex mtx_a, mtx_b;
// ✅ 推荐:用 scoped_lock 同时加多个锁,自动避免死锁
void transfer(Account& from, Account& to, int amount) {
    std::scoped_lock lock(mtx_a, mtx_b); // 自动按地址顺序加锁
    from.balance -= amount;
    to.balance += amount;
}

std::mutex 不可复制、不可移动,成员变量需显式初始化

因为 std::mutex 禁用了拷贝和移动构造/赋值,如果你把它作为类成员,又没写构造函数,编译器生成的默认构造函数会尝试调用其默认构造 —— 这没问题;但一旦你写了自定义构造函数却忘了初始化 mutex,就会编译失败。

典型错误写法:

触站AI
触站AI

专业的中文版AI绘画生成平台

下载
class Counter {
    std::mutex mtx;
    int value;
public:
    Counter(int v) : value(v) {} // ❌ 编译错误:mtx 未被初始化
};

正确写法:

  • 用成员初始化器列表显式调用 mtx()(默认构造)
  • 或直接在声明处默认初始化:std::mutex mtx{};
  • 不要试图 new std::mutex 后裸指针管理 —— 容易泄漏,且失去 RAII 优势
class Counter {
    std::mutex mtx;
    int value;
public:
    Counter(int v) : mtx(), value(v) {} // ✅ 显式初始化
    // 或:Counter(int v) : value(v) {} // ✅ C++11 起,未显式初始化也会调用默认构造
};

std::mutex 不能跨线程释放,也不能重复 unlock

每个 std::mutex 只能由加锁它的同一线程 unlock,否则行为未定义(常见表现是程序崩溃或断言失败)。这和 pthread_mutex_t 的 PTHREAD_MUTEX_ERRORCHECK 类似,但 C++ 标准不保证报错,更危险。

典型误用场景:

  • std::lock_guard 对象从一个线程 move 到另一个线程(无效,且违反 RAII 设计)
  • 在 lambda 中捕获 mutex 并在线程池里调用(lambda 执行在线程池线程上,但 lock_guard 在创建线程上构造)
  • 手动调用 unlock() 后再次调用(即使没异常)

记住:锁的生命周期和加锁线程强绑定。只要坚持用 std::lock_guard / std::scoped_lock,就能天然规避这些问题 —— 因为它们只在当前帧存在,不可能跨线程传递。

真正容易被忽略的是:某些封装类(比如带缓存的单例、对象池)内部用了 mutex,但对外没暴露线程安全契约。调用前务必确认文档,或自己加锁 —— 别假设“它应该线程安全”。

热门AI工具

更多
DeepSeek
DeepSeek

幻方量化公司旗下的开源大模型平台

豆包大模型
豆包大模型

字节跳动自主研发的一系列大型语言模型

通义千问
通义千问

阿里巴巴推出的全能AI助手

腾讯元宝
腾讯元宝

腾讯混元平台推出的AI助手

文心一言
文心一言

文心一言是百度开发的AI聊天机器人,通过对话可以生成各种形式的内容。

讯飞写作
讯飞写作

基于讯飞星火大模型的AI写作工具,可以快速生成新闻稿件、品宣文案、工作总结、心得体会等各种文文稿

即梦AI
即梦AI

一站式AI创作平台,免费AI图片和视频生成。

ChatGPT
ChatGPT

最最强大的AI聊天机器人程序,ChatGPT不单是聊天机器人,还能进行撰写邮件、视频脚本、文案、翻译、代码等任务。

相关专题

更多
lambda表达式
lambda表达式

Lambda表达式是一种匿名函数的简洁表示方式,它可以在需要函数作为参数的地方使用,并提供了一种更简洁、更灵活的编码方式,其语法为“lambda 参数列表: 表达式”,参数列表是函数的参数,可以包含一个或多个参数,用逗号分隔,表达式是函数的执行体,用于定义函数的具体操作。本专题为大家提供lambda表达式相关的文章、下载、课程内容,供大家免费下载体验。

211

2023.09.15

python lambda函数
python lambda函数

本专题整合了python lambda函数用法详解,阅读专题下面的文章了解更多详细内容。

191

2025.11.08

Python lambda详解
Python lambda详解

本专题整合了Python lambda函数相关教程,阅读下面的文章了解更多详细内容。

58

2026.01.05

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

405

2023.07.18

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

584

2023.08.10

线程和进程的区别
线程和进程的区别

线程和进程的区别:线程是进程的一部分,用于实现并发和并行操作,而线程共享进程的资源,通信更方便快捷,切换开销较小。本专题为大家提供线程和进程区别相关的各种文章、以及下载和课程。

613

2023.08.10

Golang处理数据库错误教程合集
Golang处理数据库错误教程合集

本专题整合了Golang数据库错误处理方法、技巧、管理策略相关内容,阅读专题下面的文章了解更多详细内容。

125

2026.02.06

java多线程方法汇总
java多线程方法汇总

本专题整合了java多线程面试题、实现函数、执行并发相关内容,阅读专题下面的文章了解更多详细内容。

49

2026.02.06

1688阿里巴巴货源平台入口与批发采购指南
1688阿里巴巴货源平台入口与批发采购指南

本专题整理了1688阿里巴巴批发进货平台的最新入口地址与在线采购指南,帮助用户快速找到官方网站入口,了解如何进行批发采购、货源选择以及厂家直销等功能,提升采购效率与平台使用体验。

681

2026.02.06

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
国外Web开发全栈课程全集
国外Web开发全栈课程全集

共12课时 | 1万人学习

进程与SOCKET
进程与SOCKET

共6课时 | 0.4万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号