GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • 卡码笔记-最强八股文
  • 计算机基础
  • Python
  • C++
  • Java
  • Go
  • ChatGPT充值
  • Claude充值
  • 国内使用Claude
  • 中转站推荐
  • 🔥大模型🔥
  • 大模型面经
  • Java面经
  • C++面经

This view

  • Original page
  • New address

GeezerVison is showing notes.kamacoder.com — C++11多线程编程与锁:mutex、lockguard、uniquelock、条件变量、原子操作

# 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 只保证单个操作的原子性,不保证多个操作之间的一致性。

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

评论

验证登录状态...

You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.