当前位置: 首页 > news >正文

C++11 Thread 线程库入门教程

C++11 标准正式引入了<thread>线程库,为原生 C++ 提供了跨平台的多线程编程能力。本文将从基础用法入手,详细讲解如何利用该库创建、管理线程,包括线程的启动、等待、分离等核心操作,帮助开发者快速掌握 C++ 多线程编程的基础要点。

线程的创建

在 C++11 中创建线程的核心是实例化std::thread对象,该对象需要绑定一个可调用对象作为线程的执行入口 —— 可调用对象可以是普通函数、函数对象(仿函数)、Lambda 表达式等。

基本语法格式:

#include <thread> // 实例化线程对象,绑定执行函数和参数 std::thread 线程对象名(可调用对象, 参数列表...);

创建线程后,必须通过join()等待线程执行完成,或通过detach()将线程分离至后台运行,否则会触发未定义行为。

基础示例:创建简单线程输出文本

#include <iostream> #include <thread> // 线程执行函数 void print_greeting() { std::cout << "Hello from new thread!" << std::endl; } int main() { // 创建线程并绑定执行函数 std::thread t(print_greeting); // 等待线程执行完毕 t.join(); return 0; }

向线程传递参数

线程函数支持接收参数,传递方式分为值传递和引用传递两种,需注意不同传递方式的语法细节:

  1. 值传递:直接将参数传入std::thread构造函数,参数会被拷贝到线程栈中;
  2. 引用传递:必须使用std::ref()包装引用参数,否则编译器会将引用视为值传递,导致编译错误。

示例代码

#include <iostream> #include <thread> #include <string> // 值传递参数 void print_msg(const std::string& msg) { std::cout << "Message: " << msg << std::endl; } // 引用传递参数 void increase_num(int& num) { ++num; } int main() { // 1. 值传递示例 std::string hello = "Hello Thread!"; std::thread t1(print_msg, hello); t1.join(); // 2. 引用传递示例 int count = 0; // 必须用std::ref包装引用,否则编译失败 std::thread t2(increase_num, std::ref(count)); t2.join(); std::cout << "Count after increment: " << count << std::endl; return 0; }

等待线程执行完成(join)

join()方法会阻塞当前线程(通常是主线程),直到目标线程执行完毕。当需要确保线程执行结果被正确处理、资源被释放时,必须调用该方法。

多线程等待示例

#include <iostream> #include <thread> #include <string> void print_thread_id(const std::string& id) { std::cout << "Executing " << id << std::endl; } int main() { // 创建两个并行线程 std::thread t1(print_thread_id, "Thread 1"); std::thread t2(print_thread_id, "Thread 2"); // 等待t1执行完成 t1.join(); // 等待t2执行完成 t2.join(); // 所有线程执行完毕后才会执行此行 std::cout << "All threads have finished execution" << std::endl; return 0; }

分离线程(detach)

detach()方法会将线程与std::thread对象解耦,让线程转入后台运行(成为 "守护线程"),主线程无需等待其完成。分离后的线程由操作系统接管,执行完毕后自动释放资源。

注意事项

  • 线程分离后,无法再调用join()等待其完成;
  • 需确保主线程不会过早退出,否则可能导致分离线程被强制终止,引发未定义行为。

分离线程示例

#include <iostream> #include <thread> #include <string> void background_task(const std::string& task_name) { std::cout << "Background task [" << task_name << "] running..." << std::endl; } int main() { std::thread t(background_task, "Task 1"); // 分离线程,使其在后台运行 t.detach(); std::cout << "Thread detached, main thread continues..." << std::endl; // 主线程短暂休眠,确保分离线程有时间执行(仅为演示) std::this_thread::sleep_for(std::chrono::milliseconds(100)); return 0; }

joinable () 方法的使用

joinable()std::thread的成员方法,返回布尔值:

  • true:线程未被join()detach(),可执行等待 / 分离操作;
  • false:线程已完成、已分离,或线程对象为空,无法执行等待 / 分离操作。

若对非 joinable 的线程调用join()detach(),会抛出std::system_error异常,因此建议在操作前先通过joinable()判断。

示例代码

#include <iostream> #include <thread> void simple_task() { std::cout << "Thread task started" << std::endl; } int main() { std::thread t(simple_task); // 先判断线程是否可操作,再执行join if (t.joinable()) { t.join(); std::cout << "Thread joined successfully" << std::endl; } return 0; }

常见错误与注意事项

  1. 未处理线程状态:创建线程后未调用join()detach(),主线程退出时会触发程序崩溃或未定义行为;
  2. 共享数据未同步:多线程访问共享变量时未使用互斥锁(std::mutex)等同步机制,会导致数据竞争、结果错乱;
  3. 异常未捕获:线程内抛出的未捕获异常会直接终止程序,需在线程函数内通过try-catch捕获并处理;
  4. 分离线程的生命周期:主线程退出前需确保分离线程完成核心逻辑,避免线程被强制终止。

总结

  1. C++11std::thread通过绑定可调用对象创建线程,必须通过join()等待完成或detach()分离,否则会引发未定义行为;
  2. 向线程传递引用参数需使用std::ref()包装,joinable()可用于判断线程是否可执行等待 / 分离操作;
  3. 多线程编程需注意共享数据同步、异常捕获,以及分离线程的生命周期管理,避免数据竞争和程序崩溃。
http://www.jsqmd.com/news/529363/

相关文章:

  • Qwen3-4B场景应用:快速打造个人知识问答与逻辑推理助手
  • 解决CANdb++ Editor显示德文乱码问题:从配置文件到重装的全流程指南
  • 微电网领域的重磅突破:构网型逆变器环流抑制方案
  • 办公隐私保护利器:Boss-Key老板键的5大核心功能深度解析
  • 基于Vue3与TypeScript构建高可用AI聊天机器人的实战指南
  • 嘎嘎降AI批量处理教程:多篇论文同时处理的操作完整流程
  • GyverShift库详解:74HC595/165移位寄存器驱动与GPIO扩展
  • 如何在5分钟内免费解锁付费内容:Bypass Paywalls Clean终极教程
  • EcomGPT-中英文-7B电商模型与YOLOv8联动:视频带货中的实时商品检测与描述生成
  • 如何通过Win11Debloat实现Windows系统终极优化:隐私保护与性能提升完整指南
  • Cosmos-Reason1-7B实战案例:机器人环境感知与安全决策生成教程
  • 嘎嘎降AI深度改写模式完整教程:AI率70%以上的论文怎么处理
  • 从入门到进阶:Claude 的 MCP、Skills、Subagent 和 Plugin 怎么用?
  • 不用邀请码了!Qclaw 公测开启,手把手教你打开“龙虾工作室”功能
  • Win11Debloat:系统深度优化实现Windows性能与隐私双重提升
  • Zettlr全平台部署与优化指南:从安装到高效写作
  • 打破语言壁垒:obsidian-i18n插件全攻略
  • 炉石传说脚本终极配置指南:3步实现自动化游戏体验
  • Matlab数据处理大揭秘:线性回归与曲线拟合实战
  • 工业相机选型避坑指南:CCD和CMOS到底怎么选?附实战参数对比表
  • 华硕笔记本轻量级控制工具:告别臃肿,提升效率的终极解决方案
  • Chatbot实操跟练:从零构建高可用对话系统的实战指南
  • 告别嘈杂背景音!ClearerVoice-Studio语音增强功能实测与技巧分享
  • Leather Dress Collection环境部署:Ubuntu22.04+PyTorch2.0+SD1.5兼容性验证
  • 在线生成工具(画图类)
  • 2023年信息素养大赛Python复赛(北京)(含题库答题软件账号)
  • lychee-rerank-mm保姆级教程:如何用lychee debug模式调试自定义指令
  • OpenClaw资源监控:Qwen3-32B+RTX4090D任务运行时指标可视化
  • 从零构建Linux智能安防中枢:LVGL9.0、FFmpeg与OpenCV的融合实践
  • Windows服务器安全自查:3种隐藏账号检测与清理实战(附注册表操作截图)