C++多线程相关应用
一、多线程基础
1. 线程创建与管理
#include <thread>
#include <iostream>
void task(int id) {
std::cout << "Thread " << id << " executing\n";
}
int main() {
std::thread t1(task, 1); // 创建线程
std::thread t2([](){
// Lambda表达式创建线程
std::cout << "Lambda thread\n";
});
t1.join(); // 等待线程结束
t2.join();
// detach示例(谨慎使用)
std::thread t3([]{
/* 后台任务 */ });
t3.detach();
}
AI 代码解读
2. 线程生命周期管理
join()
:阻塞等待线程结束detach()
:分离线程(失去控制权)- RAII包装器:
class ThreadGuard { std::thread& t; public: explicit ThreadGuard(std::thread& t_) : t(t_) { } ~ThreadGuard() { if(t.joinable()) { t.join(); // 或根据需求选择detach } } };
AI 代码解读
二、互斥量(Mutex)应用
1. 基础锁机制
#include <mutex>
std::mutex mtx;
int shared_data = 0;
void safe_increment() {
std::lock_guard<std::mutex> lock(mtx); // RAII自动解锁
++shared_data;
}
// 递归锁示例
std::recursive_mutex rec_mtx;
void recursive_func(int n) {
std::lock_guard<std::recursive_mutex> lock(rec_mtx);
if(n > 0) recursive_func(n-1);
}
AI 代码解读
2. 死锁预防
// 使用std::lock同时锁定多个互斥量
std::mutex mtx1, mtx2;
void safe_process() {
std::unique_lock<std::mutex> lock1(mtx1, std::defer_lock);
std::unique_lock<std::mutex> lock2(mtx2, std::defer_lock);
std::lock(lock1, lock2); // 原子化锁定
// 临界区操作
}
AI 代码解读
三、条件变量(Condition Variable)
1. 生产者-消费者模型
#include <queue>
#include <condition_variable>
std::mutex mtx;
std::condition_variable cv;
std::queue<int> data_queue;
void producer() {
for(int i=0; i<5; ++i) {
{
std::lock_guard<std::mutex> lock(mtx);
data_queue.push(i);
}
cv.notify_one(); // 通知消费者
}
}
void consumer() {
while(true) {
std::unique_lock<std::mutex> lock(mtx);
cv.wait(lock, []{
return !data_queue.empty(); }); // 防止虚假唤醒
int data = data_queue.front();
data_queue.pop();
lock.unlock();
std::cout << "Consumed: " << data << std::endl;
if(data == 4) break;
}
}
AI 代码解读
2. 条件变量使用要点
- 始终在循环中检查条件
- 使用
notify_all()
广播通知多个等待线程 - 注意通知时机,避免丢失信号
四、原子变量(Atomic)
1. 基础使用
#include <atomic>
std::atomic<int> counter(0); // 无需锁的线程安全计数器
void atomic_increment() {
for(int i=0; i<1000; ++i) {
counter.fetch_add(1, std::memory_order_relaxed);
}
}
// 测试代码
std::thread t1(atomic_increment);
std::thread t2(atomic_increment);
t1.join(); t2.join();
std::cout << "Final counter: " << counter << std::endl; // 正确输出2000
AI 代码解读
2. 内存序选择
内存序 | 特性 | 使用场景 |
---|---|---|
memory_order_relaxed | 无顺序保证 | 计数器等简单操作 |
memory_order_consume | 数据依赖排序 | 很少使用 |
memory_order_acquire | 加载操作前的访问可见 | 锁获取 |
memory_order_release | 存储操作后的修改可见 | 锁释放 |
memory_order_seq_cst | 全局顺序一致(默认) | 需要严格顺序的场景 |
五、综合应用案例
1. 线程池实现
#include <vector>
#include <future>
class ThreadPool {
std::vector<std::thread> workers;
std::queue<std::function<void()>> tasks;
std::mutex queue_mutex;
std::condition_variable condition;
bool stop = false;
public:
ThreadPool(size_t threads) {
for(size_t i=0; i<threads; ++i) {
workers.emplace_back([this] {
while(true) {
std::function<void()> task;
{
std::unique_lock<std::mutex> lock(queue_mutex);
condition.wait(lock,
[this]{
return stop || !tasks.empty(); });
if(stop && tasks.empty()) return;
task = std::move(tasks.front());
tasks.pop();
}
task();
}
});
}
}
template<class F, class... Args>
auto enqueue(F&& f, Args&&... args) -> std::future<decltype(f(args...))> {
using return_type = decltype(f(args...));
auto task = std::make_shared<std::packaged_task<return_type()>>(
std::bind(std::forward<F>(f), std::forward<Args>(args)...)
);
std::future<return_type> res = task->get_future();
{
std::lock_guard<std::mutex> lock(queue_mutex);
if(stop) throw std::runtime_error("enqueue on stopped ThreadPool");
tasks.emplace([task](){
(*task)(); });
}
condition.notify_one();
return res;
}
~ThreadPool() {
{
std::lock_guard<std::mutex> lock(queue_mutex);
stop = true;
}
condition.notify_all();
for(std::thread &worker : workers)
worker.join();
}
};
AI 代码解读
六、性能优化与陷阱
1. 锁粒度控制
// 错误示例:大粒度锁
std::mutex big_lock;
void process_data() {
std::lock_guard<std::mutex> lock(big_lock); // 锁住整个函数
// 长时间操作...
}
// 优化:细粒度锁
struct DataPart {
std::mutex mtx;
int value;
};
DataPart part1, part2;
void process_part(DataPart& part) {
std::lock_guard<std::mutex> lock(part.mtx);
// 操作单个数据部分
}
AI 代码解读
2. 虚假唤醒防护
std::condition_variable cv;
bool ready = false; // 必须的条件判断变量
// 正确写法
cv.wait(lock, []{
return ready; });
// 错误写法(可能虚假唤醒)
while(!ready) cv.wait(lock);
AI 代码解读
3. 原子操作陷阱
std::atomic<bool> flag(false);
int non_atomic_data = 0;
void thread1() {
non_atomic_data = 42; // ①
flag.store(true); // ②
}
void thread2() {
if(flag.load()) {
// ③
std::cout << non_atomic_data; // ④ 可能看到0或42
}
}
// 需要memory_order_release/acquire保证可见性
AI 代码解读
七、现代C++新特性
1. std::async异步操作
#include <future>
auto future = std::async(std::launch::async, []{
std::this_thread::sleep_for(1s);
return 42;
});
// 等待结果
std::cout << future.get() << std::endl;
AI 代码解读
2. 读写锁(C++17)
#include <shared_mutex>
std::shared_mutex rw_mutex;
void reader() {
std::shared_lock lock(rw_mutex); // 共享锁
// 读操作...
}
void writer() {
std::unique_lock lock(rw_mutex); // 独占锁
// 写操作...
}
AI 代码解读
八、调试与检测工具
Thread Sanitizer(TSan):
clang++ -fsanitize=thread -g program.cpp
AI 代码解读Mutex死锁检测:
// 使用std::scoped_lock(C++17) std::mutex mtx1, mtx2; std::scoped_lock lock(mtx1, mtx2); // 自动死锁避免
AI 代码解读性能分析工具:
- Perf
- Intel VTune
- Valgrind的DRD工具