卡码笔记-最强八股文
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
首页
计算机基础
C++
Java
Go
🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经
简历专栏
代码随想录 (opens new window)
  • 本栏必读

    • 关于本专栏
    • C++学习路线
    • C++面试题系优化
  • 基础与语法

  • 面向对象

  • STL 与容器

  • 内存管理

  • C++11 与现代 C++

    • C++11中的新特性有哪些
    • C++11中的多线程编程
      • 简要回答
      • 详细回答
      • 知识拓展
    • 左值引用和右值引用的区别
    • 移动语义有什么作用,原理是什么
    • 完美转发的作用及实现
    • 说一下c++中stdmove与stdforward的区别
    • 说一下lambda函数
    • 仿函数与lambda性能对比
    • C++中的RAII机制
    • C++中的异常处理机制
    • C++中的协程概念及实现
  • 智能指针

  • 并发与 I/O

# C++11多线程编程与锁

面试官问:"C++11 的多线程和锁机制了解吗?lock_guard 和 unique_lock 有什么区别?"

多线程是 C++ 后端面试的重头戏。很多人能说出 mutex 和 lock_guard,但问到 unique_lock 为什么能配合条件变量、死锁怎么避免,就答不上来了。关键是理解这些组件之间的配合关系。

# 简要回答

C++11 通过 <thread>、<mutex>、<condition_variable>、<atomic> 四个头文件提供了完整的多线程支持:

  • std::thread:创建和管理线程
  • std::mutex:互斥锁,保护共享数据
  • lock_guard / unique_lock:RAII 锁管理器,防止忘记解锁
  • condition_variable:线程间等待-通知机制
  • std::atomic:无锁原子操作,适合简单数据同步

# 详细回答

线程管理

std::thread 接受任何可调用对象(函数指针、lambda、仿函数)作为线程入口。创建后必须 join()(等待结束)或 detach()(分离),否则析构时程序终止。

互斥锁体系

  • std::mutex:最基本的互斥锁,不可重入
  • std::recursive_mutex:同一线程可多次加锁(递归场景)
  • std::timed_mutex:支持超时的互斥锁,try_lock_for() 避免永久阻塞

RAII 锁管理

直接用 mutex.lock() / unlock() 容易忘记解锁或异常时泄漏。RAII 包装器解决这个问题:

  • lock_guard:构造时加锁,析构时解锁,中间不能手动控制。简单、轻量、够用就用它
  • unique_lock:功能更强——支持延迟加锁、手动 lock/unlock、转移所有权。条件变量必须用它,因为 wait() 需要临时释放锁

条件变量

condition_variable 实现"等某个条件满足再继续"的模式。典型用法:生产者-消费者。wait() 会原子地释放锁并挂起线程,被 notify_one() / notify_all() 唤醒后重新加锁继续执行。

原子操作

std::atomic<T> 对简单类型(int、bool、指针)提供无锁的原子读写,比 mutex 开销小得多。适合计数器、标志位等简单同步场景,复杂逻辑还是得用锁。

C++11 多线程同步机制

# 知识拓展

面试官可能追问:

Q1: lock_guard 和 unique_lock 有什么区别?

lock_guard 更轻量,构造即加锁、析构即解锁,中间不能动。unique_lock 更灵活,支持延迟加锁(std::defer_lock)、手动 lock/unlock、配合条件变量使用。日常保护临界区用 lock_guard 就够了,需要条件变量或者需要中途解锁时才用 unique_lock。

Q2: 什么是死锁?怎么避免?

两个线程各持有一把锁,又都在等对方的锁,谁也不放手——永久阻塞。避免方法:统一加锁顺序(所有线程都先锁 A 再锁 B)、用 std::lock() 一次性锁多个 mutex、用 RAII 保证异常时也能解锁、用 timed_mutex 加超时兜底。

Q3: 条件变量为什么必须配合 unique_lock?

因为 wait() 内部要做两件事:释放锁(让其他线程能修改条件)和重新加锁(被唤醒后继续操作共享数据)。lock_guard 不支持中途释放锁,只有 unique_lock 能做到。

Q4: atomic 和 mutex 怎么选?

简单的单变量读写(计数器、标志位)用 atomic,零锁开销。涉及多个变量的复合操作(比如同时修改 balance 和 log)必须用 mutex,因为 atomic 只保证单个操作的原子性,不保证多个操作之间的一致性。

Last Updated: 5/23/2026, 4:43:26 PM

← C++11中的新特性有哪些 左值引用和右值引用的区别 →

评论

验证登录状态...

侧边栏 侧边栏
夜间模式 夜间
卡码简历 卡码简历
代码随想录 代码随想录
卡码投递表 卡码投递表🔥
2026实习校招群 2026群
添加客服微信 2026实习校招客服微信 PS:通过微信后,请发送姓名-学校-年级-2026实习/校招
支持卡码笔记 支持卡码笔记
鼓励/支持/赞赏Carl 卡码笔记赞赏码
1. 如果感觉本站对你很有帮助,也可以请Carl喝杯奶茶,金额大小不重要,心意已经收下
2. 希望大家都能梦想成真,有好的前程,加油💪