C++ 互斥量、锁与条件变量详解
本文详细介绍了C++多线程编程中的关键同步机制:互斥量、锁和条件变量。互斥量(std::mutex)用于保护共享资源,确保线程安全访问;锁(std::lock_guard/std::unique_lock)提供RAII风格的锁管理,其中unique_lock支持更灵活的控制;条件变量(std::condition_variable)实现线程间通信,等待特定条件成立。文章对比了互斥量与信号量的区别,
C++ 互斥量、锁与条件变量详解
1. 互斥量(Mutex)
- 定义:互斥量是C++多线程编程中用于保护共享资源的同步机制,确保同一时间只有一个线程可以访问特定代码段或资源。
- 核心API:
std::mutex:基本互斥锁,需手动管理锁的生命周期。std::lock_guard:RAII风格的锁管理,构造时自动上锁,析构时自动解锁。std::unique_lock:更灵活的锁管理,支持手动控制锁的生命周期。
2. 锁(Lock)
- 作用:锁是互斥量的执行单元,通过
lock()和unlock()方法控制对共享资源的访问。 - 关键特性:
- 独占性:同一时刻仅允许一个线程持有锁,其他线程尝试加锁时会阻塞或失败。
- RAII:推荐使用
std::lock_guard和std::unique_lock实现自动锁管理,避免死锁。
3. 条件变量(Condition Variable)
- 定义:条件变量用于线程间等待特定条件成立并被其他线程唤醒的同步机制。
- 核心API:
wait():阻塞线程直到被通知或条件成立。notify_one():唤醒一个等待线程。notify_all():唤醒所有等待线程。
- 使用场景:线程A等待队列非空,线程B推入任务并通知A。
4. 典型用法示例
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 等待条件成立
std::cout << "Worker thread: Condition met!" << std::endl;
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true; // 设置条件
}
cv.notify_one(); // 唤醒等待线程
t.join();
return 0;
}
5. 注意事项
- 线程安全:互斥量和条件变量必须成对使用,确保线程安全。
- 性能:
std::lock_guard和std::unique_lock比原始lock()/unlock()更高效。 - 虚假唤醒:条件变量可能因系统原因虚假唤醒,需重新检查条件。
总结:互斥量和锁是C++多线程编程中基础的同步手段,条件变量则用于更复杂的线程间通信。通过
std::mutex、std::lock_guard、std::unique_lock和std::condition_variable实现高效且安全的线程同步。
互斥量与信号量区别
1. 核心概念
- 互斥量(Mutex):用于保护临界区,确保同一时刻只有一个线程访问共享资源。
- 信号量(Semaphore):用于线程间同步或资源计数控制,允许多个线程同时访问资源。
2. 主要区别
| 特性 | 互斥量(Mutex) | 信号量(Semaphore) |
|---|---|---|
| 用途 | 保护临界区,防止资源竞争 | 同步或资源计数控制 |
| 线程所有权 | 持有线程必须释放 | 无线程所有权限制 |
| 计数值 | 二值(0/1) | 可初始化为 >1 的值 |
| 同时访问 | 同一时刻仅允许一个线程访问 | 可允许多个线程同时访问(计数值 > 1) |
| 复杂性 | 简单,专注于互斥 | 更灵活,可用于多种同步场景 |
3. 关键特性对比
- 互斥量:
- 二值状态(0/1),仅允许一个线程持有。
- 持有线程必须释放,避免死锁。
- 优先级继承机制,解决优先级反转问题。
- 信号量:
- 计数值可为非负整数,允许多个线程同时访问。
- 无线程所有权限制,可跨线程释放。
- 无优先级继承机制,适用于资源计数控制。
4. 应用场景
- 互斥量:保护共享资源,防止并发修改。
- 信号量:实现资源池管理或线程同步。
总结:互斥量和信号量在功能上存在显著差异,互斥量专注于资源独占访问,信号量则用于资源计数和线程同步。选择时需根据具体需求(如是否允许多线程访问、是否需要优先级继承)来决定。
锁与条件变量
1. 锁(Lock)
锁是C++多线程编程中用于保护共享资源的同步机制,确保同一时间只有一个线程可以访问特定代码段或资源。核心类型包括:
-
std::mutex:基本互斥锁,需手动管理锁的生命周期。 -
std::lock_guard:RAII风格的锁管理,构造时自动上锁,析构时自动解锁。 -
std::unique_lock:更灵活的锁管理,支持手动控制锁的生命周期。
2. 条件变量(Condition Variable)
条件变量用于线程间等待特定条件成立并被其他线程唤醒的同步机制。核心API包括:
-
wait():阻塞线程直到被通知或条件成立。 -
notify_one():唤醒一个等待线程。 -
notify_all():唤醒所有等待线程。
3. 典型用法示例
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 等待条件成立
std::cout << "Worker thread: Condition met!" << std::endl;
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true; // 设置条件
}
cv.notify_one(); // 唤醒等待线程
t.join();
return 0;
}
4. 注意事项
- 线程安全:锁和条件变量必须成对使用,确保线程安全。
- 性能:
std::lock_guard和std::unique_lock比原始lock()/unlock()更高效。 - 虚假唤醒:条件变量可能因系统原因虚假唤醒,需重新检查条件。
总结:锁(
std::mutex、std::lock_guard、std::unique_lock)用于资源保护,条件变量(std::condition_variable)用于线程间通信。通过RAII机制实现高效且安全的线程同步。
std::unique_lock 与 std::lock_guard 区别详解
1. 核心功能对比
| 特性 | std::lock_guard |
std::unique_lock |
|---|---|---|
| 设计目标 | 简单、高效、不可手动控制锁 | 灵活、支持手动控制锁、条件变量配合 |
| RAII管理 | 自动加锁/解锁,生命周期结束自动释放 | 自动加锁/解锁,支持延迟加锁、手动控制 |
| 锁所有权 | 无所有权转移,不可复制 | 支持所有权转移(可移动) |
| 条件变量 | 不支持(需std::unique_lock) |
支持(参数传递给std::condition_variable::wait()) |
2. 关键区别
-
锁控制能力:
std::lock_guard:构造时立即加锁,析构时自动解锁,不支持中途释放或重新获取锁。std::unique_lock:支持延迟加锁(std::defer_lock)、手动加锁/解锁(lock()/unlock()),适合复杂场景。
-
所有权管理:
std::lock_guard:不可复制,不可转移(std::unique_lock可移动)。std::unique_lock:支持所有权转移(std::move()),避免资源竞争。
-
条件变量配合:
std::lock_guard:不支持(需std::unique_lock)。std::unique_lock:可作为参数传递给std::condition_variable::wait(),实现线程间通信。
3. 典型用法示例
cppCopy Code
// 使用 std::lock_guard std::mutex mtx; void simple_lock() { std::lock_guard<std::mutex> lock(mtx); // 自动加锁 // 临界区代码 } // 自动解锁 // 使用 std::unique_lock void complex_lock() { std::unique_lock<std::mutex> lock(mtx, std::defer_lock); // 延迟加锁 if (some_condition) { lock.lock(); // 手动加锁 } // 临界区代码 lock.unlock(); // 手动解锁 }
4. 适用场景
-
std::lock_guard:适用于简单作用域内全程需要锁的场景,如文件操作、数据结构修改。 -
std::unique_lock:适用于需要更灵活控制锁的场景,如条件变量等待、锁所有权转移。
总结:
std::lock_guard提供简单高效的锁管理,std::unique_lock则提供更灵活的锁控制和条件变量支持。选择时需根据具体需求(如是否需延迟加锁、条件变量配合)来决定。
std::unique_lock条件变量
#include <iostream>
#include <thread>
#include <mutex>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
bool ready = false;
void worker() {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{ return ready; }); // 等待条件成立
std::cout << "Worker thread: Condition met!" << std::endl;
}
int main() {
std::thread t(worker);
std::this_thread::sleep_for(std::chrono::seconds(1));
{
std::lock_guard<std::mutex> lock(mtx);
ready = true; // 设置条件
}
cv.notify_one(); // 唤醒等待线程
t.join();
return 0;
}
std::unique_lock提供lock()/unlock()接口,支持手动控制锁cv.wait(lock, pred):原子解锁lock,阻塞线程,等待通知或谓词成立wait退出后自动重新锁定lock,确保线程安全- 支持延迟加锁(
std::defer_lock),避免不必要的锁竞争 - 与
std::condition_variable完美配合,实现高效线程间通信
更多推荐

所有评论(0)