第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 1
sync_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)
- 🚧 典型并发问题检测与预防(死锁、数据竞争)