用std::thread分段打印易出错,因std::cout非线程安全且i++非原子操作,需用std::atomic_int保证计数、std::mutex保护输出,或纯互斥锁方案,避免竞态与输出粘连。

用 std::thread 分段打印容易出错?先看同步问题
直接用多个 std::thread 各自循环打印,大概率输出乱序甚至重复/跳号——因为没有保护共享的计数器或输出流。C++ 标准输出 std::cout 本身不是线程安全的,多个线程同时写会崩。
- 别用全局变量 + 多线程裸递增:
i++不是原子操作,竞态条件必现 - 别对
std::cout做无保护调用:即使数字没错,换行也可能粘连(比如 “12\n34\n” 变成 “1234\n\n”) - 分段任务(如线程0打1-25、线程1打26-50)可行,但必须提前算好边界,且不能依赖运行时动态取号
std::atomic_int + 互斥锁双保险最稳
既要保证计数器不冲突,又要确保每次 std::cout 输出完整。推荐组合:用 std::atomic_int 管数字,用 std::mutex 护输出。
#include <thread>
#include <mutex>
#include <atomic>
#include <iostream>
std::atomic_int counter{1};
std::mutex cout_mutex;
void print_worker() {
while (true) {
int n = counter.fetch_add(1, std::memory_order_relaxed);
if (n > 100) break;
std::lock_guard<std::mutex> lock(cout_mutex);
std::cout << n << '\n';
}
}
int main() {
std::thread t1(print_worker);
std::thread t2(print_worker);
t1.join(); t2.join();
}
注意:fetch_add 返回旧值,所以判断 n > 100 才退出;std::memory_order_relaxed 足够,因为仅需计数不依赖其他内存操作。
只用 std::mutex 也行,但性能稍低
如果不想引入原子操作,纯靠锁也能做,只是每次都要抢锁——包括读和改计数器,比原子操作重。
组合式C++代码评审方案,融合静态分析、AI推理、多轮迭代评审和C++专项检查,适用于PR审查、增量代码审查、全项目评审和代码质量评分,触发词包括review cpp、cpp代码评审、C++review、代码审查。
立即学习“C++免费学习笔记(深入)”;
- 定义
int counter = 1和std::mutex mtx - 每次循环:加锁 → 读
counter→ 判断是否 ≤100 → 输出 →counter++→ 解锁 - 缺点:锁竞争更频繁,尤其线程多时,可能卡在锁上等半天
为什么不用 std::condition_variable?
这题不需要唤醒等待、也不需要精确调度顺序。条件变量适合“等某个条件成立再干活”,比如“等缓冲区有数据再消费”。而本题是“抢着干完100个活”,用原子+锁或纯锁更直白高效。
强行套 std::condition_variable 反而增加复杂度:要维护状态变量、虚假唤醒处理、额外 notify 开销——没收益还易写错。
真正要注意的是:线程数别设太多(比如开100个线程打100个数),上下文切换开销会吃掉所有优势;2~4个线程足够。


















