子线程不能直接写主线程栈上局部变量,会导致崩溃或未定义行为;应将共享数据置于堆上并用 std::shared_ptr 管理生命周期、std::mutex 保护访问,或对简单类型使用 std::atomic。

子线程直接写主线程局部变量会崩溃
不能这么做。主线程的栈上局部变量(比如 int x = 0;)只在主线程栈帧里有效,子线程访问它属于未定义行为——常见表现是程序随机崩溃、数据错乱或静默失败。哪怕加了 std::mutex 也救不回来,因为栈内存生命周期根本不跨线程。
用 std::shared_ptr + std::mutex 保护堆上共享状态
真正安全的做法是把要共享的数据放到堆上,并用智能指针管理生命周期,再用互斥锁控制访问。典型结构:
std::shared_ptr<int> shared_x = std::make_shared<int>(0);
std::mutex x_mutex;
std::thread t([&]() {
std::lock_guard<std::mutex> lock(x_mutex);
*shared_x = 42; // 安全:堆内存 + 锁保护
});
t.join();
-
std::shared_ptr确保对象在所有线程访问完才销毁,避免悬空指针 - 锁必须覆盖所有读写操作,包括
*shared_x解引用前后 - 别用
std::unique_ptr—— 无法被多个线程同时持有
用 std::atomic 替代锁处理简单类型
如果只读写基础类型(int、bool、指针),且操作是原子的(如赋值、自增),std::atomic 更轻量、无锁、不易死锁:
std::atomic<int> atomic_x{0};
std::thread t([&]() {
atomic_x.store(100, std::memory_order_relaxed); // 或 atomic_x = 100;
});
t.join();
assert(atomic_x.load() == 100); // 安全
-
std::memory_order_relaxed足够用于单纯数值更新;需要同步其他内存操作时才升级为acquire/release - 不支持
std::atomic<std::string>这类复杂类型,编译直接报错 - 注意:
atomic_x++是原子的,但++(*ptr)(对普通指针)不是
避免传引用或指针到栈变量进线程函数
这是新手最常踩的坑。下面代码看着像能跑,实际危险:
立即学习“C++免费学习笔记(深入)”;
int local = 0;
std::thread t([&local]() { local = 1; }); // ❌ 危险!local 可能在子线程执行前就析构了
t.detach(); // 更糟:主线程结束,local 彻底失效
- 用
[&local]捕获栈变量引用 → 子线程可能访问已销毁内存 - 用
[local]值捕获 → 修改的是副本,主线程看不到 - 正确做法:要么用堆分配 + 智能指针,要么用
std::async返回结果,而不是“修改主线程变量”
真正难的不是加锁或用 atomic,而是想清楚“这个变量是否真的需要被多线程修改”。多数情况下,应该让子线程计算结果并返回,由主线程决定怎么合并——而不是共享、竞争、加锁、调试数据竞争。


















