C++11新特性之线程std::thread

C++ std::thread的定义和功能

std::thread是C++11引入的标准库类,用于创建和管理线程。通过std::thread,程序可以并发执行多个任务,从而提高效率。

功能与作用:

  1. 创建线程:可以启动一个线程执行某个函数或任务。
  2. 管理线程:允许主线程与子线程进行交互,如等待线程结束(join())或分离线程(detach())。
  3. 提高性能:利用多核处理器的能力并行处理。

主要成员函数

  1. std::thread::join(): 阻塞调用线程,直到被管理线程完成。
  2. std::thread::detach(): 分离线程,使其在后台运行。
  3. std::thread::joinable(): 检查线程是否可被join()或detach()。

std::thread 参考代码一

#include <iostream>
#include <thread>
#include <chrono>// 模拟任务函数
void print_numbers(const std::string& thread_name, int start, int end) {for (int i = start; i <= end; ++i) {std::cout << thread_name << " prints: " << i << std::endl;std::this_thread::sleep_for(std::chrono::milliseconds(100)); // 模拟延迟}
}int main() {std::cout << "Main thread starts." << std::endl;// 创建两个线程std::thread thread1(print_numbers, "Thread 1", 1, 5);std::thread thread2(print_numbers, "Thread 2", 6, 10);// 检查线程是否joinableif (thread1.joinable() && thread2.joinable()) {std::cout << "Both threads are joinable." << std::endl;}// 主线程等待子线程结束thread1.join();thread2.join();std::cout << "All threads completed. Main thread exits." << std::endl;return 0;
}

std::thread 参考代码一输出结果

运行后程序会交替打印两个线程的输出:

Main thread starts.
Both threads are joinable.
Thread 1 prints: 1
Thread 2 prints: 6
Thread 1 prints: 2
Thread 2 prints: 7
Thread 1 prints: 3
Thread 2 prints: 8
Thread 1 prints: 4
Thread 2 prints: 9
Thread 2Thread 1 prints:  prints: 105All threads completed. Main thread exits.

备注:
Linux 系统通过 g++ thread.cpp -o thread -lpthread 进行编译

代码一分析

  1. std::thread对象的创建:
std::thread thread1(print_numbers, "Thread 1", 1, 5);

启动线程thread1,执行print_numbers函数,传递参数。

2. 等待线程结束:

thread1.detach();

join()阻塞主线程,直到thread1完成。

3. 分离线程(可选):

thread1.detach();

线程独立运行,不再由主线程管理。

4. 线程同步:
使用std::cout时,为了避免多线程输出交错,可以加锁(未示范)。

std::thread 参考代码二

#include <iostream>
#include <thread>using namespace std;int main() {auto func1 = []() {for (int i = 0; i < 10; ++i) {cout << i << " ";}cout << endl;};std::thread t1(func1);if (t1.joinable()) {t1.detach();}auto func2 = [](int k) {for (int i = 0; i < k; ++i) {cout << i << " ";}cout << endl;};std::thread t2(func2, 20);if (t2.joinable()) { // 检查线程可否被joint2.join();}return 0;
}

std::thread 参考代码二输出结果

0 1 2 3 4 5 6 7 8 9 
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19

代码二分析

上述代码中,函数func1和func2运行在线程对象t1和t2中,从刚创建对象开始就会新建一个线程用于执行函数,调用join函数将会阻塞主线程,直到线程函数执行结束,线程函数的返回值将会被忽略。如果不希望线程被阻塞执行,可以调用线程对象的detach函数,表示将线程和线程对象分离。

如果没有调用join或者detach函数,假如线程函数执行时间较长,此时线程对象的生命周期结束调用析构函数清理资源,这时可能会发生错误,这里有两种解决办法,一个是调用join(),保证线程函数的生命周期和线程对象的生命周期相同,另一个是调用detach(),将线程和线程对象分离,这里需要注意,如果线程已经和对象分离,那就再也无法控制线程什么时候结束了,不能再通过join来等待线程执行完。

下面是对thread进行封装,避免没有调用join或者detach可导致程序出错的情况出现:

std::thread 参考代码三

#include <iostream>
#include <thread>class ThreadGuard {public:enum class DesAction { join, detach };ThreadGuard(std::thread&& t, DesAction a) : t_(std::move(t)), action_(a){};~ThreadGuard() {if (t_.joinable()) {if (action_ == DesAction::join) {t_.join();} else {t_.detach();}}}ThreadGuard(ThreadGuard&&) = default;ThreadGuard& operator=(ThreadGuard&&) = default;std::thread& get() { return t_; }private:std::thread t_;DesAction action_;
};int main() {ThreadGuard t(std::thread([]() {for (int i = 0; i < 10; ++i) {std::cout << "thread guard " << i << " " << std::endl;}std::cout << std::endl;}), ThreadGuard::DesAction::join);return 0;
}

std::thread 参考代码三输出结果

thread guard 0 
thread guard 1 
thread guard 2 
thread guard 3 
thread guard 4 
thread guard 5 
thread guard 6 
thread guard 7 
thread guard 8 
thread guard 9 

C++11还提供了获取线程id,或者系统cpu个数,获取thread native_handle,使得线程休眠等功能

std::thread 参考代码四

#include <iostream>
#include <thread>using namespace std;int main()
{auto func = [](){for (int i = 0; i < 10; ++i){cout << i << " ";}cout << endl;};std::thread t(func);if (t.joinable()){t.detach();}cout << "当前线程ID " << t.get_id() << endl;cout << "当前cpu个数 " << std::thread::hardware_concurrency() << endl;auto handle = t.native_handle(); // handle可用于pthread相关操作std::this_thread::sleep_for(std::chrono::seconds(1));return 0;
}

std::thread 参考代码四输出结果

当前线程ID thread::id of a non-executing thread
当前cpu个数 4
0 1 2 3 4 5 6 7 8 9 

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

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

相关文章

【赵渝强老师】PostgreSQL的控制文件

PostgreSQL数据库的物理存储结构主要是指硬盘上存储的文件&#xff0c;包括&#xff1a;数据文件、日志文件、参数文件、控制文件、WAL预写日志文件等等。 下面重点讨论一下PostgreSQL的控制文件。 视频讲解如下 【赵渝强老师】PostgreSQL的控制文件 控制文件记录了数据库运行…

在做题中学习(79):最小K个数

解法&#xff1a;快速选择算法 说明&#xff1a;堆排序也是经典解决问题的算法&#xff0c;但时间复杂度为&#xff1a;O(NlogK)&#xff0c;K为k个元素 而将要介绍的快速选择算法的时间复杂度为: O(N) 先看我的前两篇文章&#xff0c;分别学习&#xff1a;数组分三块&#…

【linux】shell(32)-循环控制

for循环 在 Shell 脚本中&#xff0c;for 循环是一种常见的循环结构&#xff0c;用于遍历列表、数组或命令输出。 基本语法 for 循环的基本语法如下&#xff1a; #!/bin/bash for variable in list docommands donevariable 是一个临时变量&#xff0c;用于存储每次迭代中的…

Pydantic 动态字段:使用和不使用 `@computed_field` 的对比指南

Pydantic 动态字段&#xff1a;使用和不使用 computed_field 的对比指南 安装 Pydantic不使用 computed_field 的实现特性 使用 computed_field 的实现特性 使用和不使用 computed_field 的对比适用场景分析什么时候不需要 computed_field&#xff1f;什么时候使用 computed_fi…

Docker Engine多平台镜像构建(ARM64、x64、riscv64...)

Docker Engine多平台镜像构建(ARM64、x64、riscv64…) 1. Docker Engine安装 设置 Docker 的存储库# Add Dockers official GPG key: sudo apt-get update sudo apt-get install ca-certificates curl sudo install -m 0755 -d /etc/apt/keyrings sudo curl -fsSL https://do…

连续大涨,汉王科技跑步进入AI应用舒适区

OpenAI正在进行的“12天12场直播”让行业再次沸腾&#xff0c;二级市场也在寻找AI应用的机会。这刺激了12月首周同花顺sora概念涨超11&#xff05;&#xff0c;远超同期大盘指数涨幅。 截至目前&#xff0c;“满血版”推理模型o1和月收费高达200美元的ChatGPT Pro订阅服务&…

[MySQL基础](三)SQL--图形化界面+DML

本专栏内容为&#xff1a;MySQL学习专栏 &#x1f493;博主csdn个人主页&#xff1a;小小unicorn ⏩专栏分类&#xff1a;MySql &#x1f69a;代码仓库&#xff1a;小小unicorn的代码仓库&#x1f69a; &#x1f339;&#x1f339;&#x1f339;关注我带你学习编程知识 目录 图…

基于单片机的智能灯光控制系统

摘要 现在的大部分的大学&#xff0c;都是采用了一种“绿色”的教学方式&#xff0c;再加上现在的大学生缺乏环保意识&#xff0c;所以在学校里很多的教室&#xff0c;在白天的时候灯都会打开&#xff0c;这是一种极大的浪费&#xff0c;而且随时都有可能看到&#xff0c;这是…

数据分析及应用:滴滴出行打车日志数据分析

目录 0 日志数据集介绍 1 构建数据仓库 1.1 ods创建用户打车订单表 1.2 创建分区 1.3 上传到对应分区

解决Windows与Ubuntu云服务器无法通过Socket(udp)通信问题

今天在写Socket通信代码的时候&#xff0c;使用云服务器自己与自己通信没有问题&#xff0c;但是当我们把客户端换为Windows系统的时候却无法发送信息到Linux当中&#xff0c;耗时一上午终于搞定了&#x1f612;。 问题&#xff1a; 如上图&#xff0c;当我在windows的客户端…

网络安全基本命令

网络安全基本命令 想学会网络安全,就必须学会基本的网络常用命令,才能更好的去掌握网络,保护自己的系统&#xff0c;防止入侵。我们必须学会的基本的网络命令主要是基于Windows NT平台下的基本命令&#xff0c;也就是说windows 98/windows ME的下部分命令是不能运行的。所以说&…

帝可得-运营管理App

运营管理App Android模拟器 本项目的App客户端部分已经由前端团队进行开发完成&#xff0c;并且以apk的方式提供出来&#xff0c;供我们测试使用&#xff0c;如果要运行apk&#xff0c;需要先安装安卓的模拟器。 可以选择国内的安卓模拟器产品&#xff0c;比如&#xff1a;网…

Android显示系统(07)- OpenGL ES - 纹理Texture

Android显示系统&#xff08;02&#xff09;- OpenGL ES - 概述 Android显示系统&#xff08;03&#xff09;- OpenGL ES - GLSurfaceView的使用 Android显示系统&#xff08;04&#xff09;- OpenGL ES - Shader绘制三角形 Android显示系统&#xff08;05&#xff09;- OpenGL…

二十万分之一几率:if语句变do-while卡死问题分析

背景 某次灰度发布之后没多久就收到线上ANR告警&#xff0c;经排查定位到是某个页面onCreate方法执行太久导致&#xff0c;而火焰图中的耗时堆栈指向了我们用于监控页面启动速度的一段插桩代码&#xff0c;反编译Apk之后发现本该是if语句的代码竟变成了一个do-while语句&#…

React v19稳定版发布12.5

&#x1f916; 作者简介&#xff1a;水煮白菜王 &#xff0c;一位资深前端劝退师 &#x1f47b; &#x1f440; 文章专栏&#xff1a; 前端专栏 &#xff0c;记录一下平时在博客写作中&#xff0c;总结出的一些开发技巧✍。 感谢支持&#x1f495;&#x1f495;&#x1f495; 目…

Android笔记【17】返回数据的两种方法

目录 一、问题 二、具体分析 1、代码 2、区别 1. 目的和使用场景 resultLauncher startActivity 2. 数据传递方式 3. 返回结果的管理 4. 代码示例对比 使用 resultLauncher 启动活动并处理返回结果&#xff1a; 使用 startActivity 启动活动&#xff08;不处理返回&…

flutter修改状态栏学习

在flutter中如何动态更改状态栏的颜色和风格。 前置知识点学习 AnnotatedRegion AnnotatedRegion 是 Flutter 中的一个小部件&#xff0c;用于在特定区域中提供元数据&#xff08;metadata&#xff09;以影响某些系统级的行为或外观。它通常用于改变系统 UI 的外观&#xff…

功能篇:JAVA使用jwt

在Java中实现JWT&#xff08;JSON Web Token&#xff09;认证通常涉及以下几个步骤&#xff1a; 1. 添加依赖 2. 创建JWT工具类 3. 实现登录接口&#xff0c;生成JWT 4. 实现过滤器&#xff0c;验证JWT ### 1. 添加依赖 首先&#xff0c;你需要在项目中添加JWT库的依赖。如果…

Chrome扩展程序开发示例

项目文件夹内文件如下&#xff1a; manifest.json文件内容&#xff1a; {"manifest_version": 3,"name": "我的法宝","description": "我的有魔法的宝贝","version": "1.0","icons": {"…

前端知识1html

VScode一些快捷键 Ctrl/——注释 !——生成html框架元素 *n——生成n个标签 直接书写html的名字回车生成对应的标签 常见标签 span&#xff1a; <span style"color: red;">hello</span> <span>demo</span> span实现&#xff1a; 标题…