c++多线程(1)------创建和管理线程td::thread

  • 操作系统:ubuntu22.04
  • IDE:Visual Studio Code
  • 编程语言:C++11

算法描述

std::thread 是 C++11 标准库中用于创建和管理线程的核心类,定义在 头文件中。它使得多线程编程变得简单、类型安全且跨平台。

一、std::thread 简介

std::thread 是一个类,代表一个执行线程。你可以用它来启动一个函数(普通函数、lambda、函数对象、成员函数等)在新的线程中运行。
🔧 所需头文件:

#include <thread>

📦 常用成员函数:

函数说明
join()等待线程执行完毕(阻塞主线程)
detach()分离线程,让其在后台独立运行
get_id()获取线程的唯一 ID
joinable()判断线程是否可以 join 或 detach
swap()交换两个 thread 对象
native_handle()获取底层平台的原生线程句柄(如 pthread_t)

二、创建线程的多种方式(附示例)

  1. 使用普通函数
#include <iostream>
#include <thread>
#include <chrono>void hello() 
{std::this_thread::sleep_for(std::chrono::milliseconds(100));std::cout << "Hello from thread " << std::this_thread::get_id() << std::endl;
}int main()
{std::thread t(hello);  // 启动线程执行 hello 函数std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;t.join();  // 等待线程结束std::cout << "Thread joined." << std::endl;return 0;
}

输出示例:

Main thread ID: 1
Hello from thread 2
Thread joined.
  1. 使用带参数的函数
void print_message(const std::string& msg, int n) 
{for (int i = 0; i < n; ++i) {std::cout << msg << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(50));}
}int main()
{std::thread t(print_message, "Hello from thread!", 3);std::cout << "Main thread is running..." << std::endl;t.join();std::cout << "Thread finished." << std::endl;return 0;
}
⚠️ 注意:参数是值传递的。如果要传引用,必须用 std::ref。

✅ 正确传递引用:

void increment(int& x)
{++x;
}int main() 
{int a = 0;std::thread t(increment, std::ref(a));  // 使用 std::ref 传引用t.join();std::cout << "a = " << a << std::endl;  // 输出: a = 1return 0;
}

✅ 3. 使用 Lambda 表达式

int main()
{int local = 10;std::thread t([local](){  // 捕获 local 的副本std::cout << "Lambda: local = " << local << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));});t.join();return 0;
}
提示:如果要修改捕获的变量,使用 mutable 或传引用:
std::thread t([&local]() mutable 
{local += 5;std::cout << "Modified: " << local << std::endl;
});

✅ 4. 使用函数对象(仿函数)

struct Task 
{void operator()() const{std::cout << "Task executed in thread " << std::this_thread::get_id() << std::endl;}
};int main() 
{std::thread t(Task{});t.join();return 0;
}

✅ 5. 使用类的成员函数

class Worker 
{
public:void work(int id){std::cout << "Worker " << id << " working in thread " << std::this_thread::get_id() << std::endl;}
};int main() 
{Worker w;std::thread t(&Worker::work, &w, 42);  // &w 是对象指针,42 是参数t.join();return 0;
}

🔍 解释:&Worker::work 是成员函数指针,&w 是对象地址,42 是参数。

三、join() vs detach()

❗ 每个 std::thread 对象在析构前必须被 join 或 detach,否则程序会 std::terminate()。
✅ join():等待线程结束

std::thread t(some_function);
t.join();  // 主线程阻塞,直到 t 结束
// 此时 t 不再可 join,t.joinable() 返回 false

✅ detach():分离线程

std::thread t(some_function);
t.detach();  // 线程在后台运行,不再与 thread 对象关联
// 不能再 join,线程生命周期由系统管理
⚠️ 分离线程的风险:如果主线程结束,整个程序终止,分离线程也会被强制终止。

🧪 四、检查线程状态:joinable()

std::thread t(some_function);if (t.joinable()) 
{t.join();  // 安全调用
}
常用于异常安全代码中,确保线程被正确处理。

🧰 五、线程 ID 与当前线程操作

#include <iostream>
#include <thread>void show_id() 
{std::cout << "This thread ID: " << std::this_thread::get_id() << std::endl;
}int main() 
{std::thread t(show_id);std::cout << "Main thread ID: " << std::this_thread::get_id() << std::endl;t.join();// 让出 CPU 时间片std::this_thread::yield();// 休眠 500 毫秒std::this_thread::sleep_for(std::chrono::milliseconds(500));return 0;
}

🧱 六、线程安全与共享数据(简单示例)

#include <iostream>
#include <thread>
#include <mutex>int counter = 0;
std::mutex mtx;void increment() 
{for (int i = 0; i < 100000; ++i) {std::lock_guard<std::mutex> lock(mtx);++counter;}
}int main() 
{std::thread t1(increment);std::thread t2(increment);t1.join();t2.join();std::cout << "Final counter: " << counter << std::endl;  // 应为 200000return 0;
}
🔐 使用 std::mutex 和 std::lock_guard 保护共享变量 counter。

🚫 七、常见错误与注意事项

❌ 错误1:未调用 join 或 detach

int main()
{std::thread t([]{ std::cout << "Hello"; });return 0;  // t 析构时未 join/detach → 调用 std::terminate()
}

✅ 正确做法:

std::thread t(...);
// ...
t.join();  // 或 t.detach();

❌ 错误2:传递指针或引用时对象已销毁

std::thread t(increment, std::ref(local_var));
// 如果 local_var 是局部变量且线程未结束,可能访问已销毁内存
✅ 建议:确保线程使用的数据生命周期长于线程本身。

✅ 八、完整示例:多线程并行计算

#include <iostream>
#include <vector>
#include <thread>
#include <numeric>void accumulate(const std::vector<int>& vec, int start, int end, int& result){result = std::accumulate(vec.begin() + start, vec.begin() + end, 0);
}int main() 
{std::vector<int> data(100000, 1);  // 10万个1int sum1 = 0, sum2 = 0;std::thread t1(accumulate, std::ref(data), 0, 50000, std::ref(sum1));std::thread t2(accumulate, std::ref(data), 50000, 100000, std::ref(sum2));t1.join();t2.join();std::cout << "Total sum: " << sum1 + sum2 << std::endl;  // 100000return 0;
}

总结:std::thread 核心要点

要点说明
✅ 启动线程std::thread t(func, args…)
✅ 等待结束t.join()
✅ 后台运行t.detach()
✅ 安全检查t.joinable()
✅ 线程IDt.get_id() 或 std::this_thread::get_id()
✅ 传引用使用 std::ref()
✅ 异常安全在异常路径中也要 join/detach

掌握 std::thread 是学习 C++ 多线程的第一步。结合 mutex、condition_variable 和 future,你就能构建出高效、安全的并发程序。建议多写小例子练习传参、生命周期管理、同步等关键点。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/95599.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/95599.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Flutter环境搭建全攻略之-windows环境搭建

一&#xff0c;Flutter 官网&#xff1a;https://flutter.dev Flutter Packages官网&#xff1a;https://pub.dev 二&#xff0c;Windows 上面搭建Flutter Android运行环境 对应软件可以联系客服&#xff0c;或者网盘里面下载 1&#xff0c;Flutter Android环境搭建&#xff1a…

《Docker 零基础入门到实战:容器化部署如此简单,运维效率直接拉满》

相信你对封面图上的「Docker 鲸鱼」图标并不陌生 —— 它正是解决「开发环境能跑&#xff0c;生产环境崩了」的容器化神器&#xff01;Docker 通过打包应用与依赖到轻量容器&#xff0c;实现了「一次构建&#xff0c;到处运行」&#xff0c;彻底消除环境不一致的痛点。本文从 D…

Spring Security 深度学习(六): RESTful API 安全与 JWT

目录 1. 引言&#xff1a;无状态认证的崛起2. JWT (JSON Web Token) 核心概念2.1 什么是JWT&#xff1f;2.2 JWT的组成&#xff1a;Header, Payload, Signature2.3 JWT的工作原理2.4 JWT的优缺点与适用场景 3. Spring Security中的JWT集成策略3.1 禁用Session管理与CSRF防护3.2…

无名信号量

include <myhead.h> oid *task( void *file_size)int file_size1*(int*)file_size;//打开源文件int fdopen("./hello",O_RDONLY);if(fd-1){perror("open error\n");return NULL;}//打开目标文件int fd1open("./world",O_WRONLY);if(fd1-1)…

免费CRM系统与Excel客户管理的区别

很多中小企业在客户管理初期&#xff0c;会选择使用Excel表格进行客户数据的整理与维护。但随着业务规模扩大&#xff0c;客户信息日益复杂&#xff0c;Excel逐渐暴露出诸多局限性。此时&#xff0c;免费CRM系统应运而生&#xff0c;成为企业客户管理升级的重要选择。本文将深入…

linux Nginx服务配置介绍,和配置流程

1、Nginx 配置介绍认识Nginx服务的主配置文件 nginx.confnginx的配置文件一般在 /usr/local/nginx/conf/下&#xff0c;然后直接vim nginx.com 即可编辑1.1 全局配置介绍全局配置位于主配置文件最顶部&#xff0c;作用于整个Nginx服务进程&#xff0c;影响服务的资源分配、运行…

文字识别接口-文字识别技术-ocr api

文字识别接口&#xff0c;顾名思义&#xff0c;就是一种将图像文字或手写文字转换为可编辑文本的技术。文字识别接口&#xff0c;基于深度学习算法与自主ocr核心实现多种场景字符的高精度识别与结构化信息提取&#xff0c;现已被广泛应用于银行、医疗、财会、教育等多个领域。随…

DeepSeek R1大模型微调实战-llama-factory的模型下载与训练

文章目录概要1.下载模型2.llama factory 训练模型2.1 模型微调2.2 模型评估2.3 模型对话2.4 导出模型3.硬件选择概要 LLaMA Factory 是一个简单易用且高效的大型语言模型训练与微调平台。通过它&#xff0c;用户可以在无需编写任何代码的前提下&#xff0c;在本地完成上百种预…

C++ map和set

C参考文献&#xff1a;cplusplus.com - The C Resources Network 目录 一、序列式容器和关联式容器 二、set系列 &#xff08;1&#xff09;set类的介绍 &#xff08;2&#xff09;set的构造和迭代器 &#xff08;3&#xff09;set的接口 1.insert​编辑 2.find和erase 3…

头一次见问这么多kafka的问题

分享一篇粉丝朋友整理的面经&#xff0c;第一次遇见问那么多kafka的问题&#xff0c;看看他是怎么回答的。 先来看看 职位描述&#xff1a; 岗位职责&#xff1a; 负责基于 Go 的后端服务的设计、开发和维护&#xff1b;参与系统架构设计&#xff0c;确保系统的高可用性、高性能…

自底向上了解CPU的运算

文章目录 引言 CPU如何实现逻辑运算 NMOS和PMOS 基于MOS管组合下的逻辑门运算 逻辑运算下运算的实现 ALU的诞生 CPU的诞生 关于二进制运算的研究 十进制转二进制基础换算 为什么负数要使用补码进行表示 为什么反码就能解决正负数相加问题,我们还需要用补码来表示负数呢? 小数…

apache poi与Office Open XML关系

以下内容来自AI https://ecma-international.org/publications-and-standards/standards/ecma-376/ 官方规范 https://poi.apache.org/components/oxml4j/index.html java中针对Office Open XML的实现 Apache poi中各个组件 https://poi.apache.org/components/index.html …

S32K328上芯片内部RTC的使用和唤醒配置

1&#xff1a;RTC介绍 1.1 RTC基础功能介绍 参考《S32K3xx Reference Manual》&#xff0c;S32K328芯片内部自带RTC功能&#xff0c;并且支持从低功耗状态下唤醒设备&#xff1b;1.2 RTC电源介绍 由以下三张图可知 1&#xff1a;RTC由V11供电&#xff0c;V11依赖外部V15供电&am…

【Python】数据可视化之分类图

目录 条形图 箱形图 散点图 分簇散点图 小提琴 分簇小提琴 条形图 条形图是一种直观的图表形式&#xff0c;它通过不同长度的矩形条&#xff08;即“条形”&#xff09;来展示数值变量的中心趋势估计值&#xff0c;其中每个矩形的高度直接对应于该组数据的某个中心量度&…

RabbitMQ模型详解与常见问题

项目demo地址&#xff1a;https://github.com/tian-qingzhao/rabbitmq-demo 一、RabbitMQ组件概念 1.1 Server&#xff1a;接收客户端的连接&#xff0c;实现AMQP实体服务。 1.2 Connection&#xff1a;连接 应用程序与Server的网络连接&#xff0c;TCP连接。 1.3 Channel&…

网络:相比于HTTP,HTTPS协议到底安全在哪?

网络&#xff1a;相比于HTTP&#xff0c;HTTPS协议到底安全在哪&#xff1f; 我们知道HTTPS也是一种应用层协议&#xff0c;它在HTTP的基础上有一层加密&#xff0c;因为HTTP的数据传输都是以明文方式传输的&#xff0c;所以加密主要是为了防止数据在传输的时候被篡改 今天我…

AI 基础设施新范式,百度百舸 5.0 技术深度解析

本文整理自 2025 年 8 月 29 日百度云智大会 —— AI 算力平台专题论坛&#xff0c;百度智能云 AI 计算首席科学家王雁鹏的同名主题演讲。大家下午好&#xff01;昨天在主论坛&#xff0c;我们正式发布了百度百舸 AI 计算平台 5.0&#xff0c;并展示了多项亮眼的性能数据。今天…

IO进程线程;多线程;线程互斥同步;互斥锁;无名信号量;条件变量;0905

思维导图多线程打印ABC运用无名面量 实现进程同步#include<myhead.h> //定义 无名信号量 sem_t sem1; sem_t sem2; sem_t sem3; //线程1 void* task1(void *arg) {while(1){sem_wait(&sem1);printf("A");fflush(stdout);sleep(1);sem_post(&sem2);} } …

固高 GTS-800 运动控制卡完全使用指南:从硬件部署到高阶应用

固高 GTS-800 系列运动控制卡作为中端工业控制领域的标杆产品,以其 8-16 轴同步控制能力、丰富的插补功能和稳定的性能,广泛应用于激光加工、PCB 制造、精密装配等自动化设备中。本文将系统讲解 GTS-800 的硬件架构、开发环境搭建、核心功能实现及工程实践技巧,帮助工程师快…

STM32F103_Bootloader程序开发15 - 从Keil到vscode + EIDE + GCC的迁移实践

导言 STM32 - Embedded IDE - GCC - 如何在工程中生成.bin格式固件 STM32 - Embedded IDE - GCC - 使用 GCC 链接脚本限制 Flash 区域 STM32 - Embedded IDE - GCC - 如何在工程中定义一段 NoInit RAM 内存 STM32 - Embedded IDE - GCC - 如何将编译得到的.bin固件添加CRC32校验…