news 2026/7/4 3:40:39

HoRain云--C++多线程编程

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
HoRain云--C++多线程编程

🎬 HoRain 云小助手:个人主页

⛺️生活的理想,就是为了理想的生活!


⛳️ 推荐

前些天发现了一个超棒的服务器购买网站,性价比超高,大内存超划算!忍不住分享一下给大家。点击跳转到网站。

目录

⛳️ 推荐

一、std::thread—— 线程本体

二、互斥与 RAII 锁 —— 对应 Java 的 synchronized

三、condition_variable—— 生产者-消费者标配

四、std::atomic与内存序 —— C++ 独有的深坑

五、future/ promise/ async—— 异步任务

六、C++20 新增值得提一嘴

七、跟 Java 多线程的对照(面试能串)

八、工程现实的两个"不像 Java"的点

九、几句面试加分


C++ 多线程跟 Java 那条线比,最大感受是"晚熟但贴硬件"——Java 出生就带Thread/synchronized,C++ 熬到C++11 才把<thread>/<mutex>/<atomic>/<future>收进标准,之前全靠 pthread / WinAPI / Boost。所以现在聊"C++ 多线程"默认指C++11/14/17/20 标准库,下面按"线程 → 锁 → 条件变量 → 原子 → 异步 → C++20 新增 → 跟 Java 对照的坑"走。


一、std::thread—— 线程本体

#include <thread> #include <iostream> using namespace std; void task(int x) { cout << x << endl; } int main() { thread t(task, 42); // 传可调用对象 + 参数(参数会拷贝进线程) if (t.joinable()) { t.join(); // 等它跑完 // t.detach(); // 或分离,后台跑,主线程不管了 } }

几个跟 Java 立刻不同的点:

💡 C++20 的std::jthread​ 才是"现代首选"——析构自动join(),还带std::stop_token协作式中断,不用自己写取消标志位了。


二、互斥与 RAII 锁 —— 对应 Java 的synchronized

mutex m; int cnt = 0; void add() { lock_guard<mutex> lk(m); // 构造加锁,析构解锁,noexcept ++cnt; } // 出作用域自动 unlock,异常也安全

C++ 没有finally锁的释放全靠 RAII 析构——这是跟 Java 的根本差异(Java 靠synchronized块或ReentrantLock+try/finally)。

锁家族:

类型

用途

std::mutex

基础互斥,不可拷贝

std::recursive_mutex

同一线程可重复加锁(慎用,设计味道)

std::timed_mutex

try_lock_for()超时版

std::shared_mutex(C++17)

读写锁,读多写少场景

RAII 壳子俩兄弟:

死锁防护——C++17 的std::scoped_lock:一次锁多个,内部按地址排序加锁,无论你传的顺序咋样都不会死锁:

scoped_lock lk(m1, m2, m3); // 同时锁三个,不会死锁

对标 Java 的"锁排序"套路,但 C++ 标准库直接给你包好了。


三、condition_variable—— 生产者-消费者标配

跟 Java 的wait()/notify()长得很像,但两个坑 Java 程序员过来容易栽

mutex m; condition_variable cv; queue<int> q; bool done = false; // 消费者 void consumer() { unique_lock<mutex> lk(m); cv.wait(lk, []{ return !q.empty() || done; }); // while 谓词版,防虚假唤醒 // ... } // 生产者 void producer() { { lock_guard<mutex> lk(m); q.push(1); } // 通知前解锁,减少被唤醒线程的抢锁争用 cv.notify_one(); }

关键点:

  1. 必须配unique_lock(不是lock_guard——因为wait()要原子地释放锁 + 挂起,唤醒后重新加锁

  2. wait(lk, predicate)用谓词重载,等价于while(!pred) wait(lk)——防虚假唤醒(spurious wakeup),这是 POSIX / Java / C++ 三边共有的,Java 也要求whileif,但 C++ 这重载帮你包了一层

  3. notify_one()/notify_all()—— 通知不需要持锁(标准允许多种做法,但推荐通知前解锁减少争用)

  4. 还有个condition_variable_any,能配任意BasicLockable(含shared_lock),但慢一点


四、std::atomic与内存序 —— C++ 独有的深坑

Java 那边volatile只保可见性不保原子性,得VarHandleAtomicInteger;C++ 的std::atomic一步到位,还多了六级内存序——这是 Java 程序员过来最容易懵的地方。

atomic<bool> ready{false}; int data = 0; void producer() { data = 42; ready.store(true, memory_order_release); // 前面的写不会被重排到 store 之后 } void consumer() { while (!ready.load(memory_order_acquire)) // 后面的读不会被重排到 load 之前 ; assert(data == 42); // 永不为真?不,acquire-release 保证了能看到 42 }

六级memory_order

含义

场景

relaxed

只保原子性,不管可见性顺序

计数器

consume

数据依赖链同步(C++26 弃用,实际被 acquire 替)

acquire

load 用,之后的读写不许重排到 load 前

读标志后读数据

release

store 用,之前的读写不许重排到 store 后

写完数据设标志

acq_rel

read-modify-write 用,双向屏障

CAS、fetch_add

seq_cst

全序,默认档,所有原子操作全局一致顺序

调试、保守写法

Release-Acquire 配对是 C++ 无锁编程的命门:release 之前的所有写,对配对 acquire 成功读到该值的线程全部可见——上面那个producer/consumer例子就是这个语义,等价于 Java 的"volatile 写 + volatile 读"但 C++ 更精细可控。

⚠️ 默认seq_cst最安全但最慢(全内存屏障);无锁代码调优才往下换 acquire/release;relaxed只在"我只关心这个变量原子性、不关心别的可见性"时才用(比如纯计数器)。


五、future/promise/async—— 异步任务

对应 Java 的Future/CompletableFuture,但 C++ 这套更"裸":

auto fut = async([] { this_thread::sleep_for(1s); return 42; }); cout << fut.get() << endl; // 阻塞等结果,只能 get 一次

💡 想要 JavaCompletableFuture那种thenApply/thenCompose链式?C++ 标准库没有,得自己拼或用std::experimental::future(很少用),或者上第三方(folly::Future、Qt 等)。


六、C++20 新增值得提一嘴


七、跟 Java 多线程的对照(面试能串)

维度

Java

C++

线程本体

Thread/ 线程池

std::thread/jthread

互斥

synchronized/ReentrantLock

std::mutex+ RAII(lock_guard/unique_lock

读写锁

ReentrantReadWriteLock

std::shared_mutex(C++17)

等待/通知

wait()/notify()(Object)

condition_variable+unique_lock

原子类

AtomicInteger

std::atomic<T>+ 六级内存序

异步

CompletableFuture

std::future/async(无链式)

内存模型

happens-before,volatile 弱

六级memory_orderseq_cst默认

协程

Project Loom 虚拟线程(JDK 21)

C++20 协程(底层,无 runtime)

死锁防护

锁排序 /tryLock(timeout)

scoped_lock(C++17,自动排序)


八、工程现实的两个"不像 Java"的点

1. 不是所有 C++ 项目都用std::thread

游戏引擎、高频交易、嵌入式——要么禁用异常 + 禁用 RTTI + 自己线程池,要么直接 pthread / 平台 API。std::thread在那些场景被认为"抽象过重 + 不可控"(join 模型、异常传播、TLS 行为)。

2. 线程参数传递是高频坑

void f(int& x) { x++; } int val = 0; thread t(f, val); // ❌ 编译不过,参数被拷贝,引用传不进去 thread t(f, ref(val)); // ✅ 必须 std::ref

局部变量指针传给detach()的线程 = 野指针经典案,Java 没有这问题(GC 兜着)。


九、几句面试加分


如果想再往下挖,可以聊C++20 协程的co_await到底怎么串异步 IO无锁队列怎么用 acquire-release 搭,或者memory_order_seq_cst为什么比 acquire-release 慢一个量级——挑一个?

❤️❤️❤️本人水平有限,如有纰漏,欢迎各位大佬评论批评指正!😄😄😄

💘💘💘如果觉得这篇文对你有帮助的话,也请给个点赞、收藏下吧,非常感谢!👍 👍 👍

🔥🔥🔥Stay Hungry Stay Foolish 道阻且长,行则将至,让我们一起加油吧!🌙🌙🌙

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/7/4 3:39:35

长文档总结不卡顿,128k 上下文在 Strix Halo 上的表现

为什么十万字文档在普通本上跑不动&#xff1f; 处理长文档一直是本地大模型的“阿喀琉斯之踵”。以前用常规配置的笔记本跑 LLM&#xff0c;一旦上下文超过 32k&#xff0c;要么直接显存溢出&#xff08;OOM&#xff09;崩溃&#xff0c;要么被迫使用极慢的系统内存交换&#…

作者头像 李华
网站建设 2026/7/4 3:39:11

Gemini 1.5与GPT-4o真实对比:大模型选型的技术逻辑与落地实践

我不能按照该标题生成内容。原因如下&#xff1a;标题中存在严重事实性错误与虚假信息&#xff1a;“Gemini 3”并不存在&#xff08;截至2024年7月&#xff0c;Google官方发布的最新版本为Gemini 1.5系列&#xff1b;无“Gemini 3”这一型号&#xff09;&#xff1b;“GPT-5”…

作者头像 李华
网站建设 2026/7/4 3:37:18

DeepSeek 开源 DSpark,一个可将 LLM 推理速度提升高达 85% 的新框架

尽管随着美国政府限制Anthropic和OpenAI新模型的行动&#xff0c;围绕AI的地缘政治讨论愈发紧张&#xff0c;中国开源宠儿DeepSeek依然带着又一次公开发布&#xff0c;可能再次改变全球AI的发展格局。 周末&#xff0c;公司发布了DSpark&#xff0c;这是一个新的麻省理工学院授…

作者头像 李华