第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)
  • 🚧 典型并发问题检测与预防(死锁、数据竞争)
相关推荐
Yyyy4829 小时前
标签Labels、Scheduler:调度器、k8s污点与容忍度
开发语言·kubernetes
来来走走9 小时前
Android开发(Kotlin) 扩展函数和运算符重载
android·开发语言·kotlin
卿言卿语9 小时前
CC23-最长的连续元素序列长度
java·算法·哈希算法
zz-zjx9 小时前
云原生LVS+Keepalived高可用方案(二)
开发语言·php·lvs
wuwu_q9 小时前
用通俗易懂 + Android 开发实战的方式,详细讲解 Kotlin Flow 中的 retryWhen 操作符
android·开发语言·kotlin
沐怡旸10 小时前
【穿越Effective C++】条款15:在资源管理类中提供对原始资源的访问——封装与兼容性的平衡艺术
c++·面试
网络精创大傻10 小时前
PHP 与 Node.js:实际性能对比
开发语言·node.js·php
天选之女wow10 小时前
【代码随想录算法训练营——Day60】图论——94.城市间货物运输I、95.城市间货物运输II、96.城市间货物运输III
android·算法·图论
snakecy10 小时前
过关斩将编程题
开发语言·python
Blossom.11810 小时前
大模型在边缘计算中的部署挑战与优化策略
人工智能·python·算法·机器学习·边缘计算·pygame·tornado