std::thread 构造即启动但需显式 join 或 detach,否则析构时 terminate;共享数据用 mutex 或 atomic;等待用 condition_variable 而非轮询;async 适合一次性任务,future.get() 只能调用一次。

std::thread 怎么启动一个线程
直接构造 std::thread 对象就能跑起来,但必须注意:它不会自动 join 或 detach,不处理就 crash。常见错误是局部 std::thread 对象离开作用域时仍可 joinable,触发 std::terminate。
- 启动方式:
std::thread t(func, arg1, arg2),支持函数指针、lambda、成员函数(需传入对象或指针) - 必须显式调用
t.join()(等待结束)或t.detach()(分离执行),否则析构时报错 - lambda 捕获要注意:默认按值捕获,若需修改外部变量,得用
[&];但引用捕获的对象生命周期必须长于线程 - 成员函数要这样写:
std::thread t(&MyClass::func, &obj, arg),第二个参数是对象地址
多个线程怎么安全共享数据
裸用全局变量或类成员变量必然出问题,std::mutex 是最基础的防护手段,但锁的粒度和顺序直接影响正确性和性能。
- 保护临界区:用
std::lock_guard<:mutex></:mutex>自动加锁/解锁,别手写lock()/unlock() - 避免死锁:多个 mutex 要始终按相同顺序获取,比如统一按变量地址排序再 lock
-
std::atomic<int></int>适合简单类型(如计数器),比 mutex 快,但不能用于复杂操作(比如“读-改-写”逻辑仍需锁) - 不要用
std::shared_ptr管理多线程访问的资源——它的引用计数是原子的,但指向的对象内容不是
线程怎么等另一个线程结束或响应信号
std::thread::join() 是阻塞等待,但无法超时或响应中断;真正灵活的等待得靠 std::condition_variable + std::unique_lock。
-
t.join()是同步点,主线程卡住直到t完成;t.detach()后无法再控制该线程 - 条件变量必须配合
std::mutex和一个共享状态变量(如bool ready = false),wait()会自动释放锁并挂起 - 唤醒用
cv.notify_one()或cv.notify_all(),注意 notify 可以在 wait 前发生,所以要用 while 循环检查条件,不能用 if - 别用
sleep_for轮询代替 condition_variable——浪费 CPU,且有竞态
std::async 和 std::future 适合什么场景
它不是线程池,每次 std::async 默认可能新建线程(取决于 launch policy),适合“发个任务、稍后取结果”的一次性异步调用,不适合高频短任务。
立即学习“C++免费学习笔记(深入)”;
- 默认策略
std::launch::async | std::launch::deferred,具体行为由实现决定;想确保异步,显式写std::launch::async -
std::future::get()会阻塞直到结果就绪,且只能调用一次;重复调用抛std::future_error - 异常会被捕获进 future,
get()时重新抛出,这是跨线程传递错误的主要方式 - 别把
std::async当线程复用工具——没线程池,频繁调用开销大,还可能耗尽系统线程资源
线程生命周期管理、锁的范围、条件变量的虚假唤醒、future 的一次性语义——这些不是语法细节,是写对多线程的硬门槛。漏掉任何一个,程序都可能在压力下偶然崩掉,而不是立刻报错。









