C++怎么实现多线程 C++11多线程编程入门【教程】

5次阅读

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

C++怎么实现多线程 C++11多线程编程入门【教程】

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 的一次性语义——这些不是语法细节,是写对多线程的硬门槛。漏掉任何一个,程序都可能在压力下偶然崩掉,而不是立刻报错。

text=ZqhQzanResources