当前位置: 首页 > article >正文

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

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

http://www.kler.cn/a/567794.html

相关文章:

  • 云厂商中支持为物理服务器(如裸金属服务器)分配并显示公网IP
  • 【机器学习】 [代码篇] 30. KNN - sklearn 以及 自定义KNN 的实现
  • WSL,Power shell 和CMD, Git bash的区别
  • FPGA:UART串口接收(高干扰情况)
  • 【PHP脚本语言详解】为什么直接访问PHP文件会显示空白?从错误示例到正确执行!
  • 2024 通用人工智能RAG大会实践资料(脱敏)PPT合集(22份)
  • matlab2023a下载和安装教程
  • GaussDB存储过程使用(一)
  • 第十五届蓝桥杯之宝石组合
  • 复习一下什么是restful风格
  • 蓝桥 发现环
  • React实现无缝滚动轮播图
  • C语言初始化结构体变量5种方式
  • 基于yolov8的农作物叶子病害检测系统python源码+onnx模型+评估指标曲线+精美GUI界面
  • Linux下网络运维命令总结
  • 嵌入式晶振细究
  • 【异地访问本地DeepSeek】Flask+内网穿透,轻松实现本地DeepSeek的远程访问
  • JavaWeb-ServletContext应用域接口
  • 在mingw64里面编译libdatachannel的步骤记录
  • idea中或pycharm中编写Markdown文件