跳转到内容

C++ 多线程最佳实践

来自代码酷


简介[编辑 | 编辑源代码]

C++多线程编程允许程序同时执行多个任务,是现代软件开发中提升性能的关键技术。自C++11标准引入<thread>头文件以来,多线程支持已成为语言核心部分。本节将系统讲解线程管理、同步机制、性能优化及常见陷阱,帮助开发者编写高效且安全的并发代码。

线程基础[编辑 | 编辑源代码]

线程创建与生命周期[编辑 | 编辑源代码]

C++中线程通过std::thread类实现,其生命周期包含以下阶段:

graph LR A[创建] --> B[可运行] B --> C{等待资源/同步} C -->|获取资源| D[运行] D --> E[终止]

#include <iostream>
#include <thread>

void hello() {
    std::cout << "Hello from thread!\n";
}

int main() {
    std::thread t(hello);  // 线程创建
    t.join();              // 等待线程结束
    return 0;
}

输出示例:

Hello from thread!

同步机制[编辑 | 编辑源代码]

互斥锁(Mutex)[编辑 | 编辑源代码]

使用std::mutex保护共享资源:

#include <mutex>

std::mutex mtx;
int shared_data = 0;

void increment() {
    mtx.lock();
    ++shared_data;  // 临界区
    mtx.unlock();
}

更安全的RAII方式:

void safe_increment() {
    std::lock_guard<std::mutex> lock(mtx);
    ++shared_data;  // 自动释放锁
}

条件变量[编辑 | 编辑源代码]

实现线程间通信:

std::condition_variable cv;
bool ready = false;

void producer() {
    std::this_thread::sleep_for(std::chrono::seconds(1));
    ready = true;
    cv.notify_one();
}

void consumer() {
    std::unique_lock<std::mutex> lock(mtx);
    cv.wait(lock, []{ return ready; });
    std::cout << "Data ready\n";
}

高级模式[编辑 | 编辑源代码]

线程池设计[编辑 | 编辑源代码]

避免频繁创建/销毁线程的开销:

classDiagram class ThreadPool { -vector<thread> workers -queue<function<void()>> tasks -mutex queue_mutex -condition_variable condition +enqueue(F&& f) +~ThreadPool() }

原子操作[编辑 | 编辑源代码]

使用std::atomic实现无锁编程:

std::atomic<int> counter(0);

void atomic_increment() {
    counter.fetch_add(1, std::memory_order_relaxed);
}

内存序选项:

  • memory_order_seq_cst:严格顺序一致性
  • memory_order_release/acquire:同步特定操作
  • memory_order_relaxed:仅保证原子性

性能优化[编辑 | 编辑源代码]

伪共享(False Sharing)[编辑 | 编辑源代码]

当不同CPU核心修改同一缓存行中的不同变量时引发的性能问题:

graph TD A[Core 1] -->|频繁修改| B[缓存行X] C[Core 2] -->|频繁修改| D[缓存行X] B --> E[缓存一致性协议开销] D --> E

解决方案:

struct alignas(64) PaddedData {  // 64字节对齐(典型缓存行大小)
    int value1;
    // 填充剩余空间
    char padding[64 - sizeof(int)];
};

错误处理[编辑 | 编辑源代码]

异常安全[编辑 | 编辑源代码]

线程函数中的异常必须在线程内部捕获:

void risky_task() {
    try {
        // 可能抛出异常的操作
    } catch (...) {
        std::cerr << "Thread crashed!\n";
    }
}

实际案例[编辑 | 编辑源代码]

并行快速排序[编辑 | 编辑源代码]

template<typename T>
void parallel_sort(std::vector<T>& data, int threads) {
    if (data.size() < 1000 || threads <= 1) {
        std::sort(data.begin(), data.end());
        return;
    }
    
    auto mid = data.begin() + data.size()/2;
    std::thread t([&]{
        parallel_sort(std::ref(data), threads/2);
    });
    
    parallel_sort(data, threads/2);
    t.join();
    
    std::inplace_merge(data.begin(), mid, data.end());
}

最佳实践总结[编辑 | 编辑源代码]

  1. 优先使用RAII管理资源(lock_guardunique_lock
  2. 最小化临界区范围
  3. 避免线程间共享可写数据
  4. 使用thread_local替代全局变量
  5. 考虑任务并行而非数据并行
  6. 使用高层抽象(如std::async)简化代码

模板:C++多线程导航