it编程 > 编程语言 > C/C++

C++中锁的种类与使用实例详解

82人参与 2026-05-11 C/C++

关于c++中锁的种类与使用

optimized tool selectionc++ 标准库中有多种锁管理机制,各有不同的特性和适用场景:
看这段代码中使用的是 std::lock_guard,这是一个自动管理锁的工具。锁会在以下时刻释放:

锁的生命周期

.....
static std::mutex g_mutex;           // 保护 g_control / g_reply 的并发访问
.....
void handlecontrolgram(const controlgram &cg) {
    std::lock_guard<std::mutex> lk(g_mutex);  // ← 获取锁
    g_control.steeringthrottle = (uint8_t)cg.steeringthrottle;
    // ... 其他赋值操作
    g_control.controlmode = cg.controlmode;
}  // ← 函数结束时,lk 对象析构,锁自动释放

锁的释放时机

为什么使用 lock_guard?

这是 raii 模式(resource acquisition is initialization)的应用:

情形手动 lock/unlocklock_guard
正常执行✓ 释放✓ 自动释放
异常抛出锁泄露✓ 析构仍会释放
逻辑分支✗ 容易遗漏✓ 自动保证

在 c++ 中,是解决多线程数据竞争的核心工具(c++11 及以后标准提供了完善的锁机制)。针对你的 nvidia orin(ubuntu20.04,arm 架构),所有标准 c++ 锁都可以直接使用,编译时仅需链接线程库(-pthread)。

我会分 底层互斥体(锁本体)raii 自动锁管理工具(推荐必用) 两部分讲解,包含种类、特性、区别、使用场景、代码示例,最后给避坑指南。

一、前置核心知识

  1. 作用:保护共享资源(变量、文件、硬件接口),保证同一时间只有一个/指定线程访问,避免数据错乱。
  2. 核心头文件
    #include <mutex>        // c++11 基础锁
    #include <shared_mutex> // c++17 读写锁
    #include <thread>       // 线程
    
  3. 黄金原则永远用 raii 自动管理锁,不要手动 lock()/unlock()(极易忘记解锁导致死锁)。
  4. 编译命令(orin 通用):
    g++ -std=c++17 代码.cpp -o 程序 -pthread
    

二、第一部分:c++ 标准底层互斥体(锁的本体)

这是锁的核心实现,分为 独占锁、递归锁、超时锁、读写锁 4 大类,共 5 种:

互斥体类型独占性递归超时共享读写c++ 版本核心特性
std::mutex✅ 独占c++11最基础、性能最高
std::recursive_mutex✅ 独占c++11同一线程可重复加锁
std::timed_mutex✅ 独占c++11可尝试加锁,超时放弃
std::recursive_timed_mutex✅ 独占c++11递归+超时
std::shared_mutex✅ 独占✅ 读写分离c++17读共享、写独占

1.std::mutex(基础独占锁)

2.std::recursive_mutex(递归独占锁)

3.std::timed_mutex(超时独占锁)

4.std::shared_mutex(读写锁 / 共享互斥锁,c++17)

三、第二部分:raii自动锁管理工具(必用!)

直接操作底层互斥体容易忘记解锁,c++ 提供了 4 种自动锁工具,构造时加锁,析构时自动解锁

管理工具配合锁类型手动解锁超时支持多锁同时加锁核心用途
std::lock_guard所有独占锁最简单、最常用(默认首选)
std::unique_lock所有独占锁灵活锁(配合条件变量、手动控制)
std::shared_lockshared_mutex读写锁的读模式(共享)
std::scoped_lock所有锁c++17 同时锁多个锁,防死锁

四、完整使用示例(可直接在 orin 上运行)

示例 1:基础用法std::mutex + lock_guard(首选)

最常用,保护简单共享变量:

#include <iostream>
#include <mutex>
#include <thread>
using namespace std;
mutex mtx;           // 全局互斥锁
int share_num = 0;   // 共享资源
void add_num() {
    // 构造自动加锁,离开作用域自动解锁
    lock_guard<mutex> lock(mtx); 
    share_num++;
    cout << "线程id: " << this_thread::get_id() << " 数值: " << share_num << endl;
}
int main() {
    thread t1(add_num);
    thread t2(add_num);
    t1.join();
    t2.join();
    return 0;
}

示例 2:递归锁recursive_mutex

解决递归函数加锁问题:

#include <mutex>
recursive_mutex rmtx;
void func(int n) {
    lock_guard<recursive_mutex> lock(rmtx);
    if (n > 0) func(n-1); // 同一线程重复加锁,无死锁
}

示例 3:超时锁timed_mutex + unique_lock

避免永久阻塞:

#include <mutex>
#include <chrono>
timed_mutex tmtx;
void try_lock_func() {
    // 尝试加锁,最多等待 100ms
    unique_lock<timed_mutex> lock(tmtx, chrono::milliseconds(100));
    if (lock.owns_lock()) {
        cout << "加锁成功" << endl;
    } else {
        cout << "加锁超时" << endl;
    }
}

示例 4:读写锁shared_mutex(读多写少最优)

#include <shared_mutex>
shared_mutex s_mtx;
int data = 0;
// 读线程:共享加锁,多个线程可同时读
void read_data() {
    shared_lock<shared_mutex> lock(s_mtx); 
    cout << "读取数据: " << data << endl;
}
// 写线程:独占加锁,同一时间只能一个写
void write_data(int val) {
    unique_lock<shared_mutex> lock(s_mtx); 
    data = val;
    cout << "写入数据: " << data << endl;
}

示例 5:多锁防死锁scoped_lock(c++17)

同时加多个锁,避免死锁:

mutex m1, m2;
void safe_lock() {
    // 一次性加锁 m1 和 m2,自动避免死锁
    scoped_lock lock(m1, m2); 
}

五、关键区别与选型指南(核心总结)

1. 独占锁 vs 读写锁

2. lock_guard vs unique_lock

3. 普通锁 vs 递归锁

六、避坑指南(orin 开发必看)

  1. 绝对不要手动调用 lock()/unlock()
    异常、提前 return 都会导致锁无法释放,直接死锁。
  2. 锁粒度尽可能小
    只保护共享资源,不要在锁内执行耗时操作(如网络、打印)。
  3. 避免死锁
    • 多锁必须用 scoped_lock 同时加锁;
    • 不要循环等待锁。
  4. arm 平台(orin)优化建议
    短临界区(几行代码)优先用 自旋锁std::spin_lock c++20),避免线程切换开销。

七、快速选型口诀

  1. 常规场景 → mutex + lock_guard
  2. 读多写少 → shared_mutex + shared_lock
  3. 需要灵活控制/条件变量 → unique_lock
  4. 多锁防死锁 → scoped_lock
  5. 递归调用 → recursive_mutex
  6. 不想永久等待 → timed_mutex

总结

  1. c++ 锁分底层互斥体(5种)和 raii 管理工具(4种),永远用 raii 自动管理
  2. 基础开发用 std::mutex + std::lock_guard 足够;
  3. 读多写少用读写锁,性能最优;
  4. orin(arm)编译加 -std=c++17 -pthread,代码全平台通用。

到此这篇关于关于c++中锁的种类与使用的文章就介绍到这了,更多相关c++锁的种类与使用内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!

(0)

您想发表意见!!点此发布评论

推荐阅读

C++中的引用和inline 和 nullptr全面解析

05-11

C++文件流操作方式

05-11

C++ list容器基本逻辑结构和实现原理

05-12

C++深入右值引用之移动语义与完美转发(最新推荐)

05-12

C++中strcpy()拷贝的3种写法示例详解

05-13

C语言数据类型还有哪些搞不明的

05-13

猜你喜欢

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论