C++11中引入的thread

第一部分:thread概念

一、引言

        C++11 引入了多线程编程的支持,主要是通过 <thread> 头文件中的 std::thread 类来实现的。这一特性极大地增强了 C++ 应用程序的并发处理能力,允许开发者编写能够同时执行多个任务的应用程序。

二、基本概念

        std::thread 是一个表示执行线程的类,它提供了创建和管理线程的基本功能。每个 std::thread 对象都与一个执行线程相关联。当 std::thread 对象被创建时,它会启动一个新的执行线程,该线程会执行传递给 std::thread 构造函数的函数或可调用对象。

三、构造函数

        std::thread 类有几个构造函数,但最常用的构造函数接受一个可调用对象(如函数指针、lambda 表达式、函数对象、绑定表达式等)作为参数,并可选地接受一个或多个传递给该可调用对象的参数。

四、示例

#include <iostream>  
#include <thread>  void threadFunction(int n) {  std::cout << "Thread function called with n = " << n << std::endl;  
}  int main() {  std::thread t(threadFunction, 42); // 创建一个新线程,运行 threadFunction(42)  t.join(); // 等待线程结束  return 0;  
}

五、成员函数

  • join(): 阻塞当前线程,直到与之关联的线程执行完毕。
  • detach(): 将线程与 std::thread 对象分离,允许线程独立执行。一旦分离,std::thread 对象将不再拥有任何线程,也不能再次与任何线程关联或加入。
  • get_id(): 返回线程的标识符(std::thread::id 类型)。
  • joinable(): 检查线程是否可被 join()。如果线程已经执行完毕或被分离,则返回 false;否则返回 true。
  • swap(std::thread& other): 交换两个 std::thread 对象的线程所有权。

六、注意事项

  • 资源管理:如果不调用 join() 或 detach(),std::thread 对象的析构函数会调用 std::terminate(),因为此时线程仍在运行且没有明确的处理方式。
  • 线程安全:多线程程序必须考虑数据竞争和同步问题,可能需要使用互斥锁(std::mutex)、条件变量(std::condition_variable)等同步机制。
  • 性能考量:线程的创建和销毁是昂贵的操作,应尽量减少不必要的线程创建和销毁。
  • 异常安全:如果线程函数抛出异常且未被捕获,则标准没有规定具体的行为。因此,在线程函数中应妥善处理异常。

七、多个thread对象

#include <iostream>  
#include <thread>  
#include <vector>  void doWork(int id) {  std::cout << "Thread " << id << " is running" << std::endl;  
}  int main() {  std::vector<std::thread> threads;  for (int i = 0; i < 5; ++i) {  threads.emplace_back(doWork, i);  }  for (auto& t : threads) {  t.join();  }  return 0;  
}

        这个示例展示了如何创建多个线程来并行执行相同的任务。每个线程都被加入到 std::vector<std::thread> 容器中,并在之后通过循环调用 join() 等待所有线程完成。


第二部分:多线程编程相关的特性

C++11 中的 std::thread 以及其他与多线程编程相关的特性

一、线程同步

        在多线程编程中,线程同步是一个重要的概念,它用于控制多个线程之间的执行顺序,以避免数据竞争和其他并发问题。C++11 提供了几种线程同步机制:

1. 互斥锁(Mutexes):
        std::mutex 是最基本的同步原语,它提供了一种保护共享数据免受多个线程同时访问的机制。互斥锁通过锁定和解锁操作来确保在任一时刻只有一个线程可以访问受保护的数据。
#include <iostream>  
#include <thread>  
#include <mutex>  std::mutex mtx;  
int shared_data = 0;  void increment() {  mtx.lock(); // 锁定互斥锁  ++shared_data;  mtx.unlock(); // 解锁互斥锁  
}  int main() {  std::thread t1(increment);  std::thread t2(increment);  t1.join();  t2.join();  std::cout << "Shared data: " << shared_data << std::endl;  return 0;  
}

        注意:频繁地锁定和解锁互斥锁可能会降低性能,因为线程需要等待锁变为可用。

2. 锁保护(Lock Guards):
        std::lock_guard 是一个作用域锁定的封装,它会在构造时自动锁定互斥锁,并在作用域结束时自动解锁。这有助于减少因忘记释放锁而导致的死锁问题。
#include <mutex>  std::mutex mtx;  void safe_increment() {  std::lock_guard<std::mutex> guard(mtx);  ++shared_data; // mtx 已被锁定  
}
3. 条件变量(Condition Variables):


        std::condition_variable 用于阻塞一个或多个线程,直到接收到另一个线程的通知。它通常与互斥锁一起使用,以安全地等待某个条件变为真。

#include <condition_variable>  
#include <mutex>  
#include <thread>  std::mutex mtx;  
std::condition_variable cv;  
bool ready = false;  void print_id(int id) {  std::unique_lock<std::mutex> lck(mtx);  while (!ready) cv.wait(lck); // 等待 ready 变为 true  std::cout << "Thread " << id << '\n';  
}  void go() {  std::unique_lock<std::mutex> lck(mtx);  ready = true;  cv.notify_all(); // 通知所有等待的线程  
}  int main() {  std::thread threads[10];  for (int i = 0; i < 10; ++i)  threads[i] = std::thread(print_id, i);  std::cout << "10 threads ready to race...\n";  go(); // 允许 10 个线程继续执行  for (auto& th : threads) th.join();  return 0;  
}
4. 线程局部存储(Thread-Local Storage, TLS)


        C++11 引入了线程局部存储的概念,允许变量在每个线程中都有自己的实例。这可以通过 thread_local 关键字来实现。

#include <iostream>  
#include <thread>  thread_local int tls_counter = 0;  void print_and_increment() {  ++tls_counter;  std::cout << "tls_counter = " << tls_counter << std::endl;  
}  int main() {  std::thread t1(print_and_increment);  std::thread t2(print_and_increment);  t1.join();  t2.join();  // 主线程也有自己的 tls_counter 实例  print_and_increment();  return 0;  
}

        在这个例子中,每个线程(包括主线程)都有自己的 tls_counter 实例,并且它们之间的值互不影响。

二、小结

        C++11 通过 std::thread 和其他相关的类和函数(如 std::mutex、std::lock_guard、std::condition_variable 和 thread_local)为多线程编程提供了强大的支持。然而,编写正确的多线程代码仍然是一个挑战,需要开发者深入理解线程同步和并发编程的概念。

附:c++11新增的其他性

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

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

WebLogic 漏洞复现

1、后台弱⼝令GetShell 默认账号密码&#xff1a;weblogic/Oracle123 weblogic常⽤弱⼝令&#xff1a;https://cirt.net/passwords?criteriaweblogic 这⾥注意&#xff0c; 单个账号错误密码5次之后就会⾃动锁定。 http://47.121.212.195:7001/console 2、登录后台后&#…

恒生科指八连涨,汽车股强势

9月20日电 周五&#xff0c;港股三大股指集体收涨。恒生指数涨1.36%报18258.57点&#xff0c;连续第六个交易日上涨&#xff1b;恒生科技指数涨1.43%报3703.84点&#xff0c;连续第八个交易日上涨&#xff0c;创逾两个月来新高&#xff1b;恒生中国企业指数涨1.21%报6381.5点&a…

项目扩展五:交互式:command-line interface版本的实现

项目扩展五&#xff1a;command-line interface版本的实现 一、CLI交互的设计1.为何要设计这个CLI交互2.具体设计1.启动服务2.选择信道3.选择虚拟机4.正式业务注意&#xff1a;1.消费者与生产者跟信道的关系2.消息处理回调函数的问题3.消息确认的问题 5.其他功能1.打印功能2.查…

STM32精确控制步进电机

目的&#xff1a;学习使用STM32电机驱动器步进电机&#xff0c;进行电机运动精确控制。 测试环境&#xff1a; MCU主控芯片STM32F103RCT6 &#xff1b;A4988步进电机驱动器模块&#xff1b;微型2相4线步进电机10mm丝杆滑台&#xff0c;金属丝杆安装有滑块。 10mm二相四线微型…

机器学习之非监督学习(二)异常检测(基于高斯概率密度)

机器学习之非监督学习&#xff08;二&#xff09;异常检测&#xff08;基于高斯概率密度&#xff09; 0. 文章传送1.案例引入2.高斯正态分布3.异常检测算法4.异常检测 vs 监督学习5.算法优化6.代码实现 0. 文章传送 机器学习之监督学习&#xff08;一&#xff09;线性回归、多…

C语言中数组和字符串的联系

一、C语言中&#xff0c;数组和字符串 1、C语言中&#xff0c;定义一个数组后&#xff0c;数组名保存的是这个数组的首地址。类似一个指向数组第一个元素的指针&#xff0c;但是这个指针不能重新指向。2、字符串在C语言中是通过字符数组来实现的&#xff0c;也就是说字符串还是…

【小沐学CAD】3ds Max常见操作汇总

文章目录 1、简介2、二次开发2.1 C 和 3ds Max C SDK2.2 NET 和 3ds Max .NET API2.3 3ds Max 中的 Python 脚本2.4 3ds Max 中的 MAXScript 脚本 3、快捷键3.1 3Dmax键快捷键命令——按字母排序3.2 3dmax快捷键命令——数字键3.3 3dmax功能键快捷键命令3.4 3Dmax常用快捷键——…

Elasticsearch 完整格式的 URL 进行分词,有什么好的解决方案吗?

1、问题描述 我想对完整格式的 url 进行分词&#xff0c;请问有什么好的解决方案吗&#xff1f; 比如&#xff1a;https://www.abc.com/any/path?param_1some&param-2other#title 看了官方的分词器&#xff0c;感觉没啥合适的? 预处理的话&#xff0c;又不知道该怎么处理…

Unity对象池的高级写法 (Plus优化版)

唐老师关于对物体分类的OOD的写法确实十分好&#xff0c;代码也耦合度也低&#xff0c;但是我有个简单的写法同样能实现一样的效果&#xff0c;所以我就充分发挥了一下主观能动性 相较于基本功能&#xff0c;这一版做出了如下改动 1.限制了对象池最大数量&#xff0c;多出来的…

C++11 可变的模板参数

前言 本期我们接着继续介绍C11的新特性&#xff0c;本期我们介绍的这个新特性是很多人都感觉抽象的语法&#xff01;它就是可变的模板参数&#xff01; 目录 前言 一、可变的模板参数 1.1可变的参数列表 1.2可变的参数包 1.3可变参数包的解析 • 递归展开解析 • 逗号…

微服务Docker相关指令

1、拉取容器到镜像仓库 docker pull xxx //拉取指令到 镜像仓库 例如 docker pull mysql 、docker pull nginx docker images //查看镜像仓库 2、删除资源 2.1、删除镜像仓库中的资源 docker rmi mysql:latest //删除方式一&#xff1a;格式 docker rmi 要…

【解密 Kotlin 扩展函数】扩展函数的创建(十六)

导读大纲 1.1 为第三方的类添加方法: 扩展函数 1.1 为第三方的类添加方法: 扩展函数 Kotlin 的主题之一是与现有代码的平滑集成 即使是纯 Kotlin 项目,也是构建在 Java 库之上的 如 JDK、Android 框架和其他第三方框架 而当你将 Kotlin 集成到 Java 项目中时 你还要处理尚未或不…

python爬虫:将知乎专栏文章转为pdf

欢迎关注本人的知乎主页~ 实现思路 用户输入专栏ID&#xff1a; 代码首先提示用户输入一个知乎专栏的ID&#xff0c;默认值为 c_1747690982282477569。输入的ID用于构建API请求的URL。 发送HTTP请求&#xff1a; 使用 requests.get() 向知乎API发送GET请求&#xff0c;获取指定…

【QGIS入门实战精品教程】6.1:QGIS根据属性条件查询数据(SQL表达式)

文章目录 一、字段过滤二、高级过滤(表达式)一、字段过滤 对于单个字段的查询,可以采用字段过滤,例如,从县区数据中,根据NAME字段,查找出县级市玉门市。操作为:右键县区→打开属性表: 点击左下角,选择name字段。 输入玉门市,回车,选择查找除的属性表记录,此时图斑…

【Linux】入门【更详细,带实操】

Linux全套讲解系列&#xff0c;参考视频-B站韩顺平&#xff0c;本文的讲解更为详细 目录 1、课程内容 2、应用领域 3、概述 4、 Linux和Unix 5、VMware15.5和CentOS7.6安装 6、网络连接三种方式 7、虚拟机克隆 8、虚拟机快照 9、虚拟机迁移删除 10、vmtools 11、目录…

set-ExecutionPolicy RemoteSigned 提示不是内部或外部命令,也不是可运行的程序或批处理文件

这个错误一般发生在使用命令提示符或者PowerShell窗口中找不到set-ExecutionPolicy RemoteSigned。如果你想在命令提示符或者PowerShell窗口运行set-ExecutionPolicy RemoteSigned&#xff0c;你需要搜索打开Window PowerShell ISE&#xff0c;并以管理员身份打开&#xff0c;输…

基于微信小程序的美食外卖管理系统

作者&#xff1a;计算机学姐 开发技术&#xff1a;SpringBoot、SSM、Vue、MySQL、JSP、ElementUI、Python、小程序等&#xff0c;“文末源码”。 专栏推荐&#xff1a;前后端分离项目源码、SpringBoot项目源码、Vue项目源码、SSM项目源码 精品专栏&#xff1a;Java精选实战项目…

Tomcat系列漏洞复现

CVE-2017-12615——Tomcat put⽅法任意⽂件写⼊漏洞 漏洞描述 当 Tomcat运⾏在Windows操作系统时&#xff0c;且启⽤了HTTP PUT请求⽅法&#xff08;例如&#xff0c;将 readonly初始化参数由默认值设置为false&#xff09;&#xff0c;攻击者将有可能可通过精⼼构造的攻击请求…

身份安全风险不断上升:企业为何必须立即采取行动

在推动安全AI 模型的过程中&#xff0c;许多组织已转向差异隐私。但这种旨在保护用户数据的工具是否阻碍了创新&#xff1f; 开发人员面临一个艰难的选择&#xff1a;平衡数据隐私或优先考虑精确结果。差分隐私可以保护数据&#xff0c;但通常以牺牲准确性为代价——对于医疗保…

某省公共资源交易中心爬虫逆向分析

目标网站 aHR0cHM6Ly95Z3AuZ2R6d2Z3Lmdvdi5jbi8jLzQ0L3NjenQteHEvP3VzZXJJZD02NzM4OTg2MzkyNjA3NzAzMDQmcm93SWQ9NTI1MDYyMDI2ODg0NzE2NTQ0JnRpbWU9MjAwOC0xMS0yNiZjZXJ0aWZpY2F0ZU5vPTkxNDQwOTA0NjgyNDI2MzU4QyZjZXJ0aWZpY2F0ZVR5cGU9Mjg 一、抓包分析 请求头参数加密 二、…