C++ thread线程库

thread库

std::thread 是 C++ 标准库中的一个类,用于管理和控制单个执行线程。线程允许程序并行执行多个函数,从而提高性能和响应速度。std::thread 类提供了一种便捷的方式来创建和操作线程。

1、用途

并行执行任务: 通过 std::thread,可以同时执行多个函数。

多任务处理: 可以在不同的线程中处理不同的任务,使得程序可以同时完成多个任务。

资源共享和同步: 通过 std::thread,多个线程可以共享资源,如内存和文件。为避免数据竞争和冲突,通常会使用同步机制(如 std::mutexstd::atomic)来保护共享资源。

2、关键点

线程创建和启动std::thread 在构造时立即开始执行提供的函数。

线程同步joinable() 方法检查线程是否可以被 joindetach。调用 join() 会阻塞当前线程,直到目标线程完成。

3、线程的状态
  • 默认构造、移动构造、detachjoin 后,std::thread 对象将不再表示任何线程。
  • 两个 std::thread 对象不能表示同一执行线程,且 std::thread 不能复制,但可以移动。

一、类成员

id: 表示线程的id

std::thread::id
线程id唯一表示一个线程,一旦线程结束,这个id可以复用作为另一个线程的线程id;

在这里插入图片描述

二、成员函数

1、构造函数

用于构造新的thread对象

函数原型标准
thread() noexcept;(1)(C++11 起)
thread( thread&& other ) noexcept;(2)(C++11 起)
template< class Function, class… Args > explicit thread( Function&& f, Args&&… args );(3)(C++11 起)
thread(const thread&) = delete;(4)(C++11 起)

(1) 默认构造函数:构造一个不表示新线程thread对象,即不创建新线程。

(2) 移动构造函数:将other表示的执行线程的所有权转移给新创建的线程对象thread。调用后,thread表示执行线程,而other不再表示任何线程。

(3) 函数对象和参数列表:使用给定的函数和该函数的参数列表来创建并启动一个新线程。

(4) 复制构造函数:此构造函数被删除,因此thread对象不允许复制。

1)代码测试
#include <iostream>
#include <thread>
#include <chrono>
#include <string>void func(int num,std::string str)
{std::this_thread::sleep_for(std::chrono::seconds(2));std::cout << str <<" " << num << ":" << std::this_thread::get_id() << std::endl;
}void func2()
{std::cout << "is func2" << std::endl;
}int main()
{/*未启动线程*/// std::thread thread1; // if(thread1.joinable())// {//     std::cout << "thread1 线程可被释放" << std::endl;//     thread1.join(); // } else{//     std::cout << "thread1 线程不可被释放" << std::endl;// }//std::thread thread();// if(thread.joinable())    // 非法使用// {//     thread.join();   // 非法使用// }/*构造并启动*/// std::thread thread2(func,2,"thread2");// if(thread2.joinable())// {//     std::cout << "thread2 线程可被释放" << std::endl;//     thread2.join(); // } else{//     std::cout << "thread2 线程不可被释放" << std::endl;// }    /*使用可调用对象和参数列表*/ // std::thread thread4(func,4,"thread4");// if(thread4.joinable())// {//     thread4.join();//     std::cout << "t3 线程被释放" << std::endl;// } else{//     std::cout << "t3 线程不能被释放" << std::endl;// }/*移动构造*/ // std::thread thread3(func,3,"thread3");// std::thread move_thread = std::move(thread3);// if(thread3.joinable())// {//     thread3.join();//     std::cout << "t3 线程被释放" << std::endl;// } else{//     std::cout << "t3 线程不能被释放" << std::endl;// }// if(move_thread.joinable())// {//     move_thread.join();//     std::cout << "move_thread 线程被释放" << std::endl;// } else{//     std::cout << "move_thread 线程不能被释放" << std::endl;// }/*复制构造*/// std::thread thread5(func,5,"thread5");// std::thread copy_thread(thread5);// thread5.join();// if(copy_thread.joinable())// {//     copy_thread.join();//     std::cout << "copy_thread 线程被释放" << std::endl;// } else{//     std::cout << "copy_thread 线程不能被释放" << std::endl;// }/*使用默认构造函数,延时启动线程*/// std::thread thread6; // 默认构造// thread6 = std::thread(func,6,"thread6");// if(thread6.joinable())// {//     thread6.join();//     std::cout << "thread6 线程被释放" << std::endl;// } else{//     std::cout << "thread6 线程不能被释放" << std::endl;// }return 0;
}
2)执行结果

在这里插入图片描述

2、析构函数

用于销毁 thread 对象,析构之前一定要保证没有正在运行的关联线程( 即joinable()返回true ),否则调用析构函数时会导致调用std::terminate(),从而终止程序 ,产生资源泄露和未定义行为。

注: std::terminate 函数 是一个用于处理未捕获异常的全局终止函数。当程序遇到未捕获的异常或者某些致命错误时,std::terminate 会被调用,通常会导致程序非正常退出。

函数原型标准
~thread();(C++11起)

在下列操作后 thread 对象无关联的线程(从而可安全销毁)

1.被默认构造,并没有被启动的线程对象
std::thread thread1;	// thread1没有被启动,则可以被安全销毁2.被移动构造的线程对象
std::thread t2(func, argv);
std::thread t3(std::move(t2)); // 线程对象 t2 被移动后可以被安全销毁3.调用了join()后的线程对象
t3.join();				// 线程对象 t3再调用 join()后,可以被安全销毁4.调用了detach()后的线程对象
std::thread t4(func,argv);
t4.detach();			// 线程对象 t4 在调用detach()后可以被安全销毁

经过这些操作后,std::thread 对象不再与任何线程关联,可以安全销毁。这些操作确保在销毁 std::thread 对象时不会调用 std::terminate()

1)代码测试
#include <iostream>
#include <thread>
#include <chrono>void func(std::string str)
{std::cout << str << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));
}int main()
{// std::thread t1(func,"t1");std::thread t2(func,"t2");std::thread t3(std::move(t2));std::thread t4(func,"t4");t3.join();t4.detach();return 0;
}
2)执行结果

在这里插入图片描述

3、运算符重载operator=

operator= 实际上是一个移动赋值运算符。它执行的是移动语义,将一个线程对象的所有权从一个 std::thread 对象转移到另一个 std::thread 对象。,类比移动构造。

4、joinable

检查 std::thread 对象是否活着。 若 thread 对象表示的执行线程活着则返回 true ,否则返回 false 。

函数原型标准
bool joinable() const noexcept;(C++11起)
1)代码测试
std::thread t1(func,argc);
if(t1.joinable())std::cout << "线程存活" << std::endl;
elsestd::cout << "线程死亡" << std::endl;t1.join();
if(t1.joinable())std::cout << "线程存活" << std::endl;
elsestd::cout << "线程死亡" << std::endl;
2)执行结果

在这里插入图片描述

5、get_id

获取与线程对象关联的线程的 ID 。

  • std::this::thread::get_id(); 获取当前执行线程的ID;
  • std::thread 对象调用 get_id(),获取与该对象关联的线程ID;
函数原型标准
[std::thread::id]get_id() const noexcept;(C++11 起)
1)代码测试
#include <iostream>
#include <thread>
#include <thread>
#include <mutex>    // 互斥锁头文件std::mutex mutex_lock;  // 定义互斥锁void func(std::string str)
{std::lock_guard<std::mutex> lock(mutex_lock);  // 确保线程安全std::cout << "线程 " << str << " id = " << std::this_thread::get_id() << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2)); 
}int main()
{std::thread t1(func,"t1");std::thread t2(func,"t2");{std::lock_guard<std::mutex> lock(mutex_lock);  // 确保线程安全std::thread::id t1_id = t1.get_id();std::thread::id t2_id = t2.get_id();std::cout << "t1_id = " << t1_id << std::endl;std::cout << "t2_id = " << t2_id << std::endl;    }{std::lock_guard<std::mutex> lock(mutex_lock);  // 确保线程安全std::cout << "主线程 " << " id = " << std::this_thread::get_id() << std::endl;}t1.join();t2.join();return 0;
}

注:mutex_lock 是线程互斥锁,防止控制台输出竞争,输出信息混乱。关注get_id()函数的调用即可,使用互斥锁,是为了让了输出更美观,并获得正确的输出信息。

2)执行结果

在这里插入图片描述

在这里插入图片描述

6、native_handle

用于获取与 std::thread 对象关联的底层线程句柄。 std::thread 提供了一组基本的线程管理功能,但是在某些情况下,可能需要更低级的线程管理功能,例如设置线程优先级、绑定线程到特定的 CPU 核心、或其他特定于平台的操作。 如果需要与平台特定的 API 交互,native_handle() 可以获取底层线程句柄,从而进行更精细的控制。

函数原型标准
native_handle_type native_handle();(C++11 起)(可选)
1)代码测试
#include <iostream>
#include <thread>
#include <pthread.h>    // c线程库
#include <errno.h>
#include <string.h>void func()
{std::cout << "thread ID = " << std::this_thread::get_id() << std::endl;
}int main()
{std::thread t(func);pthread_t nativeHandle = t.native_handle(); // 获取底层线程句柄// 设置线程优先级sched_param sch_params;sch_params.sched_priority = 20; // 设置优先级if (pthread_setschedparam(nativeHandle, SCHED_FIFO, &sch_params)) {std::cerr << "设置线程调度失败: " << strerror(errno) << std::endl;}t.join();return 0;
}
2)执行结果

在这里插入图片描述

注:普通用户没有权限设置优先级,可以使用 sudo 获取临时管理员权限运行。

7、hardware_concurrency

返回支持的并发线程数,这个返回值因为系统资源限制、竞争条件、硬件支持等情况,该值只能做一个参考。

函数原型标准
static unsigned int hardware_concurrency() noexcept;(C++11 起)
1)代码测试
#include <iostream>
#include <thread>
#include <mutex>std::mutex mutex_lock;void func(std::string str)
{std::lock_guard<std::mutex> lock(mutex_lock);  // 确保线程安全std::cout << "线程 " << str << " id = " << std::this_thread::get_id() << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2)); 
}int main()
{static unsigned int num = std::thread::hardware_concurrency();std::cout << "支持" << num << "个线程" << std::endl;return 0;
}
2)执行结果

在这里插入图片描述

8、join

用于阻塞当前线程,直到被 join() 的线程执行结束,被 join 的线程执行结束后,从对应的 join() 处返回。多个线程内,对同一个 std::thread 对象调用 join() 会导致未定义行为。

函数原型标准
void join();(C++11 起)

注: std::thread 对象调用 join()后,joinable() 结果为 false

1)代码测试
#include <iostream>
#include <thread>
#include <chrono>void func(std::string str)
{std::cout << str << " " << std::this_thread::get_id() << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));
}void func1(std::string str)
{std::cout << str << " " << std::this_thread::get_id() << std::endl;
}int main()
{std::thread t(func,"线程t");t.join();std::cout << "主线程: " << std::this_thread::get_id() << std::endl;std::thread t1(func1,"线程t1");std::thread t2([&t1]{t1.join();});std::thread t3([&t1] {t1.join();});t2.join();t3.join();return 0;
}
2)执行结果

在这里插入图片描述

9、detach

从 std::thread 对象分离执行线程,允许被分离的线程独立持续执行。该线程退出会自行释放资源,调用 detach 不再占有任何线程。

函数原型标准
void detach();(C++11 起)
1)代码测试
#include <iostream>
#include <thread>
#include <chrono>void func(std::string str)
{std::cout << str << " " << std::this_thread::get_id() << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));
}int main()
{std::thread t(func,"线程t");std::this_thread::sleep_for(std::chrono::seconds(2));t.detach();if(t.joinable()){std::cout << "线程t可被释放" << std::endl;}else{std::cout << "线程t自行释放" << std::endl;}return 0;
}
2)执行结果

在这里插入图片描述

10、swap

用于交换两个底层 std::thread 对象的句柄。

函数原型标准
void swap( [std::thread]& other ) noexcept;(C++11 起)
1)代码测试
#include <iostream>
#include <thread>
#include <chrono>void func(std::string str)
{std::cout << str << " " << std::this_thread::get_id() << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));
}void func1(std::string str)
{std::cout << str << " " << std::this_thread::get_id() << std::endl;std::this_thread::sleep_for(std::chrono::seconds(2));
}int main()
{std::thread t1(func,"t1");std::cout << "t1_ID = " << t1.get_id() << std::endl;std::thread t2(func1,"t2");std::cout << "t2_ID = " << t2.get_id() << std::endl;t1.swap(t2);std::cout << "t1_ID = " << t1.get_id() << std::endl;std::cout << "t2_ID = " << t2.get_id() << std::endl;t1.join();t2.join();return 0;
}
2)执行结果

在这里插入图片描述

参考资料:[ [std::thread - C++中文 - API参考文档 ] ]( std::thread - C++中文 - API参考文档 (apiref.com) )
如有谬误,请各位大佬指正。

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

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

相关文章

【Python】九种数据类型详讲(内含常见常见的字符串函数汇总)

个人主页&#xff1a;【&#x1f60a;个人主页】 系列专栏&#xff1a;【❤️Python】 文章目录 前言Number&#xff08;数字&#xff09;整数类型int &#xff08;整型&#xff0c;长整型&#xff09;float&#xff08;浮点型&#xff09;complex&#xff08;复数&#xff09;…

【基于深度学习方法的激光雷达点云配准系列之GeoTransformer】——模型部分浅析(1)

【GeoTransformer系列】——模型部分 1. create_model2. model的本质3. 模型的主要结构3.1 backbone3.2 transformer本篇继续对GeoTransformer/experiments/geotransformer.kitti.stage5.gse.k3.max.oacl.stage2.sinkhorn/下面的trainval.py进行详细的解读,主要是模型部分, 可以…

从旺店通·企业奇门到金蝶云星空通过接口配置打通数据

从旺店通企业奇门到金蝶云星空通过接口配置打通数据 对接系统&#xff1a;旺店通企业奇门 旺店通是北京掌上先机网络科技有限公司旗下品牌&#xff0c;国内的零售云服务提供商&#xff0c;基于云计算SaaS服务模式&#xff0c;以体系化解决方案&#xff0c;助力零售企业数字化智…

RuoYi-Cloudv3.6.4使用教程【2】新增子模块_使用代码生成功能,创建功能页面

目录 准备工作修改代码生成的配置信息ry-cloud中创建表 代码生成使用导入对应表代码生成代码放置菜单 启动新增模块创建数据库创建表创建配置文件_新增的模块新增logback.xml新增banner添加路由启动项目 ✨接新增子模块&#xff0c;让子模块运行起来&#xff0c;还没创建模块的…

Portainer 是一个开源的容器管理平台-非常直观好用的Docker图形化项目

在这个容器化技术大行其道的时代&#xff0c;Docker和Kubernetes几乎成了技术圈的新宠。可是管理起容器来&#xff0c;有时候还是有点头大。命令行操作对于某些小伙伴来说&#xff0c;可能还是有点不太友好。 今天开源君分享一个叫 Portainer 的开源项目&#xff0c;一个用来简…

通义千问接入进阶:流式、文件、图片、上下文

通义千问接入SSE 接入流式对话、上下文对话、图片对话、文件对话 上篇文章有很多小伙伴再问&#xff1a;开启了流式&#xff08;SSE&#xff09;如何以API的形式返回数据呢&#xff1f; 这篇文章就来给大家解惑。 实现过程 如何生成key和模型类型请翻找之前的文章&#xf…

开源大模型和闭源大模型,打法有何区别?

现阶段&#xff0c;各个公司都有自己的大模型产品&#xff0c;有的甚至不止一个。除了小部分开源外&#xff0c;大部分都选择了闭源。那么&#xff0c;头部开源模型厂商选择开源是出于怎样的初衷和考虑&#xff1f;未来大模型将如何发展&#xff1f;我们来看看本文的分享。 在对…

软件测试最全面试题及答案整理(2024最新版)

1、你的测试职业发展是什么? 测试经验越多&#xff0c;测试能力越高。所以我的职业发展是需要时间积累的&#xff0c;一步步向着高级测试工程师奔去。而且我也有初步的职业规划&#xff0c;前3年积累测试经验&#xff0c;按如何做好测试工程师的要点去要求自己&#xff0c;不断…

Linux 压测工具---ab

安装 yum -y install httpd-tools 本文用于压测k8s集群内pod&#xff0c;k8s集群master可直接测试pod ip 命令&#xff1a; ab -n 10000 -c 100 http://10.42.8.212/ 其中&#xff0c;-n表示请求数&#xff0c;-c表示并发数&#xff0c;ip必须有”/“&#xff0c;表示此目录…

洗地机品牌哪个最好用?硬核推荐五大实力爆款洗地机

在这个忙碌的时代&#xff0c;家就是我们放松的港湾&#xff0c;但要保持它的清洁与舒适常常很不容易。每天拖着疲惫的身体回家&#xff0c;还要面对地板上那些难缠的灰尘、污渍&#xff0c;真是非常让人头疼。不过&#xff0c;洗地机的出现就像是给家务清洁装上了智能引擎&…

【云WAF为您的Web防御保驾护航】

在这个数字时代&#xff0c;网络就像是一张没有尽头的大网&#xff0c;将整个世界都联系在了一起。但是&#xff0c;在这个网络的背后&#xff0c;却潜藏着数不清的安全隐患。恶意攻击、数据泄漏、网站瘫痪……各种隐患就像是隐藏在暗处的毒蛇&#xff0c;时刻都会对没有任何防…

Redis深度解析:核心数据类型与键操作全攻略

文章目录 前言redis数据类型string1. 设置单个字符串数据2.设置多个字符串类型的数据3.字符串拼接值4.根据键获取字符串的值5.根据多个键获取多个值6.自增自减7.获取字符串的长度8.比特流操作key操作a.查找键b.设置键值的过期时间c.查看键的有效期d.设置key的有效期e.判断键是否…

Google重大更新--解读Android Auto认证4.3

Google在今年五月更新了Android Auto 4.2.2版本&#xff0c;而在2024年7月他们推出了Android Auto 4.3版本&#xff0c;这是自2023年9月以来对Android Auto 4.2版本的一次重大更新。 为了确保合规性和顺利认证&#xff0c;OEM和Tire1必须确保PDK组件版本与正在认证的主机的Rece…

three.js 后期处理,物体高亮

效果图 代码 引入资源文件&#xff0c;在初始化时创建后处理对象 // 用于边缘高亮的插件// 引入后处理扩展库EffectComposer.jsimport { EffectComposer } from "three/addons/postprocessing/EffectComposer.js";// 引入渲染器通道RenderPassimport { RenderPass }…

Kafka-服务端-网络层-源码流程

整体架构如下所示&#xff1a; responseQueue不在RequestChannel中&#xff0c;在Processor中&#xff0c;每个Processor内部有一个responseQueue 客户端发送的请求被Acceptor转发给Processor处理处理器将请求放到RequestChannel的requestQueue中KafkaRequestHandler取出reque…

深度解析Java世界中的对象镜像:浅拷贝与深拷贝的奥秘与应用

在Java编程的浩瀚宇宙中&#xff0c;对象拷贝是一项既基础又至关重要的技术。它直接关系到程序的性能、资源管理及数据安全性。然而&#xff0c;提及对象拷贝&#xff0c;不得不深入探讨其两大核心类型&#xff1a;浅拷贝&#xff08;Shallow Copy&#xff09;与深拷贝&#xf…

防爆智能手机如何解决危险环境下通信难题?

在化工厂、石油行业、矿山等危险环境中&#xff0c;通信安全一直是难题。传统手机因不具备防爆功能&#xff0c;可能引发火花、爆炸等安全风险&#xff0c;让工作人员在关键时刻难以及时沟通。但如今&#xff0c;防爆智能手机的出现彻底改变了这一现状&#xff01; 安全通信&am…

手机如何充当电脑摄像头,新手使用教程分享(新)

手机如何充当电脑摄像头&#xff1f;随着科技的发展&#xff0c;智能手机已经成为我们日常生活中不可或缺的一部分。手机的摄像头除了拍摄记录美好瞬间之外&#xff0c;其实还有个妙用&#xff0c;那就是充当电脑的摄像头。手机摄像头充当电脑摄像头使用的话&#xff0c;我们就…

一分钟学习数据安全—自主管理身份SSI分布式加密密钥管理

在这篇之前&#xff0c;我们已经对SSI有了一个全局的了解。这个系列的文章可以作为一个学习笔记来参考&#xff0c;真正要实践其中的一些方案、协议&#xff0c;还需要参考专业的书籍和官方文档。作为一个SSI系列学习笔记的最后一篇&#xff0c;我们做一个简单的延伸&#xff0…

【中项第三版】系统集成项目管理工程师 | 第 9 章 项目管理概论① | 9.1 - 9.3

前言 第 9 章对应的内容选择题和案例分析都会进行考查&#xff0c;这一章节理论性较强&#xff0c;学习要以教材为准。本章分值预计在4-5分。 目录 9.1 PMBOK的发展 9.2 项目基本要素 9.2.1 项目基础 9.2.2 项目管理 9.2.3 项目成功的标准 9.2.4 项目、项目集、项目组合…