第16天:C++多线程完全指南 - 从基础到现代并发编程

第16天:C++多线程完全指南 - 从基础到现代并发编程

一、多线程基础概念

1. 线程创建与管理(C++11)

cpp 复制代码
#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. 并发与并行区别

  • 并发:交替处理多个任务(单核)
  • 并行:同时处理多个任务(多核)
cpp 复制代码
// 查看硬件支持线程数
unsigned int n = std::thread::hardware_concurrency();
std::cout << n << " concurrent threads supported\n";

二、线程同步核心机制

1. 互斥锁(mutex)与RAII

cpp 复制代码
#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. 条件变量(生产者-消费者模式)

cpp 复制代码
#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)

cpp 复制代码
#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)

cpp 复制代码
#include <atomic>

std::atomic<int> counter(0);  // 无需锁的线程安全计数器

void increment() {
    for (int i=0; i<100000; ++i) {
        ++counter;  // 原子操作
    }
}

// 测试:两个线程同时递增
// 最终结果正确为200000

四、线程安全设计模式

1. 线程局部存储(thread_local)

cpp 复制代码
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)

cpp 复制代码
#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. 死锁检测示例

cpp 复制代码
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)

cpp 复制代码
#include <semaphore>

std::counting_semaphore<5> sem(3);  // 允许3个同时访问

void limited_thread() {
    sem.acquire();
    // 访问受限资源
    sem.release();
}

2. 屏障(C++20 barrier)

cpp 复制代码
std::barrier sync_point(3);  // 等待3个线程到达

void worker() {
    // Phase 1
    sync_point.arrive_and_wait();
    
    // Phase 2(所有线程完成Phase1后继续)
}

七、常见问题解答

Q:如何检测数据竞争?

  • 使用ThreadSanitizer编译:
bash 复制代码
g++ -fsanitize=thread -g -O1 program.cpp
  • 示例输出:
bash 复制代码
WARNING: ThreadSanitizer: data race

Q:std::mutex和std::shared_mutex区别?

  • std::mutex:独占锁
  • std::shared_mutex:读写锁(C++17)
cpp 复制代码
std::shared_mutex smtx;

// 写操作使用独占锁
{
    std::unique_lock lock(smtx);
    data = new_value;
}

// 读操作使用共享锁
{
    std::shared_lock lock(smtx);
    read_data = data;
}

八、今日总结

✅ 核心掌握:

  • 🧵 线程生命周期管理(创建、等待、分离)
  • 🔒 同步原语使用场景(mutex/atomic/condition_variable)
  • 🚧 典型并发问题检测与预防(死锁、数据竞争)
相关推荐
程序员徐师兄4 分钟前
基于Python Django的人脸识别上课考勤系统(附源码,部署)
开发语言·python·django·人脸识别考勤·人脸识别上课考勤系统
Pandaconda6 分钟前
【新人系列】Golang 入门(二):基本数据类型
开发语言·笔记·后端·golang·go·字符串·数据类型
奈葵8 分钟前
动态规划/贪心算法
算法·动态规划
轩源源8 分钟前
数据结构——哈希表的实现
开发语言·数据结构·c++·算法·哈希算法·散列表·哈希桶
wanjiazhongqi10 分钟前
常见的排序算法 【复习笔记】
笔记·算法·排序
编码浪子17 分钟前
基于 Rust 与 GBT32960 规范的编解码层
java·开发语言·rust
zhengtianzuo18 分钟前
天佐.混沌钟 软件许可授权
c++
火车叨位去194918 分钟前
拼电商客户管理系统
算法
lsx20240626 分钟前
C# 类型转换
开发语言
学习使我变快乐29 分钟前
C++:内联函数
开发语言·c++