C++ 多线程实战三板斧


✅ C++ 多线程实战三板斧:干活、抢东西、传消息

抛开复杂的底层原理(比如内存序、CPU 缓存一致性),我们只讲工程中真正用得上的多线程技能

我把 C++ 多线程实战分为三大块:


第一块:怎么干活?(线程的创建与管理)

场景:你有一堆任务要跑,想让它们同时干,别排队。

1. 最基础:std::thread

C++11 引入的"线程原语",功能全但得自己组装。

cpp 复制代码
#include <iostream>
#include <thread>

// 任务函数
void work(int id) {
    for (int i = 0; i < 3; ++i) {
        std::cout << "线程 " << id << " 正在干活 " << i << "\n";
    }
}

int main() {
    std::thread t1(work, 1);
    std::thread t2(work, 2);
    std::thread t3(work, 3);

    t1.join();
    t2.join();
    t3.join();
}

实战注意

  • 必须调用 join()(或 detach()),否则程序会 terminate
  • 优先用 join()detach() 容易导致资源泄漏或未定义行为。
2. 偷懒神器:std::async

如果你只是想"异步跑个函数,等结果",这是最简单的。

cpp 复制代码
#include <iostream>
#include <future>

int calc() {
    int sum = 0;
    for (int i = 0; i < 1000000; ++i) sum += i;
    return sum;
}

int main() {
    // 异步计算
    std::future<int> fut = std::async(std::launch::async, calc);

    std::cout << "正在等结果...\n";

    int result = fut.get(); 
    std::cout << "结果是:" << result << "\n"; // 500000500000
}

实战注意

  • 务必写 std::launch::async,否则可能同步执行(不新开线程)!
  • fut.get() 会阻塞,直到任务完成。

第二块:怎么抢东西?(共享资源竞争)

场景:多个线程要改同一个变量(比如余额、计数器),不加锁会出大问题。

1. 最常用:std::mutex + std::lock_guard

就像"银行柜台",一次只能一个人进去。

cpp 复制代码
#include <iostream>
#include <thread>
#include <vector>
#include <mutex>

int balance = 100;
std::mutex mtx;

void withdraw(int id, int amount) {
    std::lock_guard<std::mutex> lock(mtx); // 自动加锁/解锁
    if (balance >= amount) {
        balance -= amount;
        std::cout << "线程 " << id << " 取了 " << amount 
                  << ",余额 " << balance << "\n";
    } else {
        std::cout << "线程 " << id << " 余额不足!\n";
    }
}

int main() {
    std::vector<std::thread> threads;
    for (int i = 0; i < 10; ++i) {
        threads.emplace_back(withdraw, i, 10);
    }
    for (auto& t : threads) t.join();
}

实战注意

  • 永远用 lock_guard,别手动 lock()/unlock()
  • 锁的范围越小越好(只包住"改数据"的代码)。
2. 高性能替代:std::atomic

如果只是操作单个整数/指针,原子操作比锁快得多。

cpp 复制代码
#include <atomic>
#include <thread>
#include <iostream>

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

void add() {
    for (int i = 0; i < 100000; ++i) {
        counter++; // 线程安全的自增
    }
}

int main() {
    std::thread t1(add), t2(add);
    t1.join(); t2.join();
    std::cout << "counter = " << counter << "\n"; // 一定是 200000
}

实战注意

  • 仅适用于简单操作(++、--、load、store)。
  • 复杂逻辑(如"if-then-update")仍需用 mutex

第三块:怎么传消息?(线程间通信)

场景:线程 A 算完数据,要告诉线程 B;或者线程 A 要等线程 B 的结果。

1. 最简单:std::promise / std::future

像"快递单":A 放数据,B 取数据。

cpp 复制代码
#include <iostream>
#include <thread>
#include <future>

void producer(std::promise<int>&& prom) {
    int result = 42;
    prom.set_value(result);
}

void consumer(std::future<int>&& fut) {
    int result = fut.get();
    std::cout << "拿到结果:" << result << "\n";
}

int main() {
    std::promise<int> prom;
    std::future<int> fut = prom.get_future();

    std::thread t1(producer, std::move(prom));
    std::thread t2(consumer, std::move(fut));

    t1.join(); t2.join();
}

实战注意

  • promisefuture 不可拷贝,只能移动
  • 适合一对一通信。
2. 实战神器:线程安全队列

工程中最常用的"生产者-消费者"模式。

cpp 复制代码
#include <queue>
#include <mutex>
#include <condition_variable>

template<typename T>
class ThreadSafeQueue {
private:
    std::queue<T> q;
    mutable std::mutex mtx;
    std::condition_variable cv;

public:
    void push(T val) {
        std::lock_guard<std::mutex> lock(mtx);
        q.push(std::move(val));
        cv.notify_one();
    }

    bool try_pop(T& val) {
        std::lock_guard<std::mutex> lock(mtx);
        if (q.empty()) return false;
        val = std::move(q.front());
        q.pop();
        return true;
    }

    void wait_and_pop(T& val) {
        std::unique_lock<std::mutex> lock(mtx);
        cv.wait(lock, [this] { return !q.empty(); });
        val = std::move(q.front());
        q.pop();
    }
};

实战注意

  • condition_variable 避免 while(true) 忙等,省 CPU。
  • 适合多生产者-多消费者场景(如任务队列、日志系统)。

🧰 总结:C++ 多线程实战三板斧

场景 推荐工具 关键注意点
异步任务 std::thread / std::async join() 别忘;asynclaunch::async
共享资源 std::mutex + lock_guard 锁粒度要小;复杂逻辑别用 atomic
线程通信 promise/future 或 线程安全队列 队列用 condition_variable 避免忙等

这样讲,是不是更贴近实际干活的场景 了?

------ 不再纠结"memory_order_relaxed 是啥",而是直接告诉你:"这么写,能跑,不出错,性能还行"。

相关推荐
fpcc1 小时前
并行编程实战——CUDA编程的Tile
c++·cuda
独自破碎E1 小时前
BISHI54货物堆放
android·java·开发语言
json{shen:"jing"}2 小时前
分割回文串
java
workflower2 小时前
易用性和人性化需求
java·python·测试用例·需求分析·big data·软件需求
小灵不想卷2 小时前
LangChain4 初体验
java·langchain·langchain4j
忍者必须死3 小时前
ConcurrentHashMap源码解析
java
顾北123 小时前
SpringCloud 系列 04:Gateway 断言 / 过滤器 / 限流 一站式落地指南
java·开发语言·数据库
闻哥3 小时前
23种设计模式深度解析:从原理到实战落地
java·jvm·spring boot·设计模式·面试
wuqingshun3141593 小时前
java创建对象的方式
java·开发语言