第16天:C++多线程完全指南 - 从基础到现代并发编程
一、多线程基础概念
1. 线程创建与管理(C++11)
#include <iostream>
#include <thread>void hello() {std::cout << "Hello from thread " << std::this_thread::get_id() << "\n";
}int main() {std::thread t1(hello);std::thread t2([](){std::cout << "Lambda thread running\n";});t1.join(); // 等待线程完成t2.join();// 输出可能交错:// Hello from thread 140245230233344// Lambda thread running
}
2. 并发与并行区别
- 并发:交替处理多个任务(单核)
- 并行:同时处理多个任务(多核)
// 查看硬件支持线程数
unsigned int n = std::thread::hardware_concurrency();
std::cout << n << " concurrent threads supported\n";
二、线程同步核心机制
1. 互斥锁(mutex)与RAII
#include <mutex>std::mutex mtx;
int shared_data = 0;void safe_increment() {std::lock_guard<std::mutex> lock(mtx); // 自动释放锁++shared_data; // 临界区操作
}int main() {std::thread threads[10];for (auto& t : threads) {t = std::thread(safe_increment);}for (auto& t : threads) {t.join();}std::cout << "Final value: " << shared_data; // 正确输出10
}
2. 条件变量(生产者-消费者模式)
#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(); // 通知消费者std::this_thread::sleep_for(std::chrono::milliseconds(100));}
}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 << "\n";if(data == 4) break;}
}
三、现代C++并发特性
1. 异步任务(std::async)
#include <future>int compute(int x) {return x * x;
}int main() {auto future = std::async(std::launch::async, compute, 12);std::cout << "Result: " << future.get(); // 输出144
}
2. 原子操作(std::atomic)
#include <atomic>std::atomic<int> counter(0); // 无需锁的线程安全计数器void increment() {for (int i=0; i<100000; ++i) {++counter; // 原子操作}
}// 测试:两个线程同时递增
// 最终结果正确为200000
四、线程安全设计模式
1. 线程局部存储(thread_local)
thread_local int tls_var = 0; // 每个线程独立副本void thread_func() {++tls_var;std::cout << "Thread " << std::this_thread::get_id() << ": " << tls_var << "\n";
}// 每个线程输出自己的递增结果
2. 线程池实现(C++17)
#include <vector>
#include <functional>
#include <queue>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>void enqueue(F&& f) {{std::lock_guard<std::mutex> lock(queue_mutex);tasks.emplace(std::forward<F>(f));}condition.notify_one();}~ThreadPool() {{std::lock_guard<std::mutex> lock(queue_mutex);stop = true;}condition.notify_all();for(auto& worker : workers)worker.join();}
};
五、并发编程陷阱与调试
1. 死锁检测示例
std::mutex m1, m2;void thread_A() {std::lock_guard<std::mutex> lock1(m1);std::this_thread::sleep_for(std::chrono::milliseconds(100));std::lock_guard<std::mutex> lock2(m2); // 可能死锁点
}void thread_B() {std::lock_guard<std::mutex> lock2(m2);std::this_thread::sleep_for(std::chrono::milliseconds(100));std::lock_guard<std::mutex> lock1(m1); // 可能死锁点
}// 解决方案:使用std::lock同时锁定多个互斥量
void safe_lock() {std::lock(m1, m2);std::lock_guard<std::mutex> lock1(m1, std::adopt_lock);std::lock_guard<std::mutex> lock2(m2, std::adopt_lock);
}
六、现代C++并发增强
1. C++20信号量(semaphore)
#include <semaphore>std::counting_semaphore<5> sem(3); // 允许3个同时访问void limited_thread() {sem.acquire();// 访问受限资源sem.release();
}
2. 屏障(C++20 barrier)
std::barrier sync_point(3); // 等待3个线程到达void worker() {// Phase 1sync_point.arrive_and_wait();// Phase 2(所有线程完成Phase1后继续)
}
七、常见问题解答
Q:如何检测数据竞争?
- 使用ThreadSanitizer编译:
g++ -fsanitize=thread -g -O1 program.cpp
- 示例输出:
WARNING: ThreadSanitizer: data race
Q:std::mutex和std::shared_mutex区别?
- std::mutex:独占锁
- std::shared_mutex:读写锁(C++17)
std::shared_mutex smtx;// 写操作使用独占锁
{std::unique_lock lock(smtx);data = new_value;
}// 读操作使用共享锁
{std::shared_lock lock(smtx);read_data = data;
}
八、今日总结
✅ 核心掌握:
- 🧵 线程生命周期管理(创建、等待、分离)
- 🔒 同步原语使用场景(mutex/atomic/condition_variable)
- 🚧 典型并发问题检测与预防(死锁、数据竞争)