参考:https://llfc.club/category?catid=225RaiVNI8pFDD5L4m807g7ZwmF#!aid/2Tuk4RfvfBC788LlqnQrWiPiEGW

1. 简历

  • 本节介绍C++线程管控,包括移交线程的归属权,线程并发数量控制以及获取线程id等基本操作。

2. 线程归属权

在这里插入图片描述

  • 比如下面,我们说明了线程归属权的转移方式
#include <iostream>
#include <thread>
#include <string>
void some_function()
{while (true){std::this_thread::sleep_for(std::chrono::seconds(1));}
}
void some_other_function()
{while (true){std::this_thread::sleep_for(std::chrono::seconds(1));}
}
int main()
{// t1 绑定some_functionstd::thread t1(some_function);// 2 转移t1管理的线程给t2,转移后t1无效std::thread t2 = std::move(t1);// 3 t1 可继续绑定其他线程,执行some_other_functiont1 = std::thread(some_other_function);// 4  创建一个线程变量t3std::thread t3;// 5  转移t2管理的线程给t3t3 = std::move(t2);// 6  转移t3管理的线程给t1t1 = std::move(t3);std::this_thread::sleep_for(std::chrono::seconds(2000));return 0;
}

在这里插入图片描述在这里插入图片描述

3. joining_thread

joinable()

bool joinable() const noexcept;
在这里插入图片描述
在这里插入图片描述

  • 曾经有一份C++17标准的备选提案,主张引入新的类joining_thread,它与std::thread类似,但只要其执行析构函数,线程即能自动汇合,这点与scoped_thread非常像。可惜C++标准委员会未能达成共识,结果C++17标准没有引入这个类,后来它改名为std::jthread,依然进入了C++20标准的议程(现已被正式纳入C++20标准)。除去这些,实际上joining_thread类的代码相对容易编写
#include <iostream>
#include <thread>
#include <string>class joining_thread
{std::thread _t;public:joining_thread() noexcept = default;template <typename Callable, typename... Args>explicit joining_thread(Callable &&func, Args &&...args): _t(std::forward<Callable>(func), std::forward<Args>(args)...) {}explicit joining_thread(std::thread t) noexcept: _t(std::move(t)) {}joining_thread(joining_thread &&other) noexcept: _t(std::move(other._t)) {}joining_thread &operator=(joining_thread &&other) noexcept{// 如果当前线程可汇合,则汇合等待线程完成再赋值if (joinable()){join();}_t = std::move(other._t);return *this;}joining_thread &operator=(joining_thread other) noexcept{// 如果当前线程可汇合,则汇合等待线程完成再赋值if (joinable()){join();}_t = std::move(other._t);return *this;}~joining_thread() noexcept{if (joinable()){join();}}void swap(joining_thread &other) noexcept{_t.swap(other._t);}std::thread::id get_id() const noexcept{return _t.get_id();}bool joinable() const noexcept{return _t.joinable();}void join(){_t.join();}void detach(){_t.detach();}std::thread &as_thread() noexcept{return _t;}const std::thread &as_thread() const noexcept{return _t;}
};
  • 使用起来比较简单,我们直接构造一个joining_thread对象即可。

在这里插入图片描述
在这里插入图片描述

4. 容器存储

在这里插入图片描述

void use_vector() {std::vector<std::thread> threads;for (unsigned i = 0; i < 10; ++i) {threads.emplace_back(param_function, i);}for (auto& entry : threads) {entry.join();}
}

5. 选择运行数量

  • 借用C++标准库的std::thread::hardware_concurrency()函数,它的返回值是一个指标,表示程序在各次运行中可真正并发的线程数量.我们可以模拟实现一个并行计算的功能,计算容器内所有元素的和
#include <iostream>
#include <thread>
#include <string>
#include <vector>
#include<algorithm>
#include<numeric>template<typename lterator,typename T>
struct accumulate_block
{void operator()(lterator first, lterator last, T& result){result += std::accumulate(first, last, result);}
};template <typename Iterator, typename T>
T parallel_accumulate(Iterator first, Iterator last, T init)
{unsigned long const length = std::distance(first, last);if (!length)return init; // ⇽-- - ①  上面的代码1处判断要计算的容器内元素为0个则返回。unsigned long const min_per_thread = 25;unsigned long const max_threads =(length + min_per_thread - 1) / min_per_thread; // 等价于ceil(length / min_per_thread)  向上取整// ⇽-- - ② 2处计算最大开辟的线程数,我们预估每个线程计算25个数据长度。unsigned long const hardware_threads =std::thread::hardware_concurrency(); // 表示程序在各次运行中可真正并发的线程数量./*但是我们可以通过std::thread::hardware_concurrency返回cpu的核数,我们期待的是开辟的线程数小于等于cpu核数,这样才不会造成线程过多时间片切换开销。*/unsigned long const num_threads =std::min(hardware_threads != 0 ? hardware_threads : 2, max_threads); // ⇽-- - ③ 3处计算了适合开辟线程数的最小值。unsigned long const block_size = length / num_threads; // ⇽-- - ④ 4处计算了步长,根据步长移动迭代器然后开辟线程计算。std::vector<T> results(num_threads);std::vector<std::thread> threads(num_threads - 1); // ⇽-- - ⑤ 5处初始化了线程数-1个大小的vector,因为主线程也参与计算,所以这里-1.Iterator block_start = first;for (unsigned long i = 0; i < (num_threads - 1); ++i){ // 6处移动步长,7处开辟线程,8处更新起始位置。Iterator block_end = block_start;std::advance(block_end, block_size); // ⇽-- - ⑥// 定义在头文件 <iterator> 中。它的作用是 将一个迭代器向前或向后移动指定的距离。threads[i] = std::thread( // ⇽-- - ⑦accumulate_block<Iterator, T>(),block_start, block_end, std::ref(results[i]));block_start = block_end; // ⇽-- - ⑧}accumulate_block<Iterator, T>()(block_start, last, results[num_threads - 1]); // ⇽-- - ⑨9处为主线程计算。for (auto& entry : threads)entry.join();                                             // ⇽-- - ⑩10 处让所有线程joinreturn std::accumulate(results.begin(), results.end(), init); // ⇽-- - ⑪ 11 处最后将所有计算结果再次调用std的accumulate算出结果。
}
void use_parallel_acc()
{std::vector<int> vec(1000000);for (int i = 0; i < 1000000; i++){vec.push_back(i);}int sum = 0;sum = parallel_accumulate<std::vector<int>::iterator, int>(vec.begin(),vec.end(), sum);std::cout << "sum is " << sum << std::endl;
}int main()
{use_parallel_acc();return 0;
}

6. 识别线程

所谓识别线程就是获取线程id,可以根据线程id是否相同判断是否同一个线程。比如我们启动了一个线程,我们可以通过线程变量的get_id()获取线程id。

std::thread t([](){std::cout << "thread start" << std::endl;
});
t.get_id();
  • 但是如果我们想在线程的运行函数中区分线程,或者判断哪些是主线程或者子线程,可以通过这总方式

std::thread t([](){std::cout << "in thread id " << std::this_thread::get_id() << std::endl;std::cout << "thread start" << std::endl;
});

std::this_thread::get_id()
t.get_id()

7. 总结

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

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

相关文章

Qt面试常问

1.QT信号与槽的底层原理&#xff1f; 底层通过元对象系统和事件循环完成的&#xff0c;能够在运行期间动态处理信号槽之间的连接与断开&#xff0c;而不是像函数调用那样在编译期间就完全确定了。元对象系统包含&#xff1a;QObject类、Q_OBJECT宏定义、moc编译器当发送一个信…

【git】错误

【成功解决】开代理 unable to access ‘https://github.com/laigeoffer/pmhub.git/’: Recv failure: Connection was reset

什么是状态机?状态机入门

状态机&#xff1a;优雅管理复杂逻辑的Python实践 在软件开发中&#xff0c;状态机&#xff08;Finite State Machine, FSM&#xff09; 是管理多状态转换的利器。它将行为分解为离散的状态、事件和转移规则&#xff0c;大幅提升代码的可读性与可维护性。本文通过Python示例解析…

【Python打卡Day41】简单CNN@浙大疏锦行

可以看到即使在深度神经网络情况下&#xff0c;准确率仍旧较差&#xff0c;这是因为特征没有被有效提取----真正重要的是特征的提取和加工过程。MLP把所有的像素全部展平了&#xff08;这是全局的信息&#xff09;&#xff0c;无法布置到局部的信息&#xff0c;所以引入了卷积神…

MySQL中InnoDB存储引擎底层原理与MySQL日志机制深入解析

MySQL的内部组件结构如下&#xff1a; 大体来说&#xff0c;MySQL 可以分为 Server 层和存储引擎层两部分。 Server层 主要包括连接器、查询缓存、分析器、优化器、执行器等&#xff0c;涵盖 MySQL 的大多数核心服务功能&#xff0c;以及所有的内置函数&#xff08;如日期、…

MCP基本概念

基本概念 现在大模型交互的热门形式&#xff1a; 第一、Agent与Tools(工具)的交互Agent需要调用外部工具和APl、访问数据库、执行代码等。> MCP 第二、Agent与Agent(其他智能体或用户)的交互Agent需要理解其他Agent的意图、协同完成任务、与用户进行自然的对话。 > A2A…

Docker容器相关命令介绍和示例

Docker 容器是镜像的运行实例。以下是常用的 Docker 容器命令及其示例&#xff1a; 1. 运行容器 docker run [选项] <镜像名> [命令]常用选项&#xff1a; -d&#xff1a;后台运行&#xff08;守护模式&#xff09;-it&#xff1a;交互式终端--name&#xff1a;指定容…

【Akshare】高效下载股票和ETF数据

在量化投资与金融数据分析的世界里&#xff0c;获取高质量的市场数据是构建有效策略的关键。Python库Akshare为我们提供了一个强大且易于使用的接口&#xff0c;可以轻松地从网络上抓取各类金融数据。本文将详细介绍如何利用Akshare下载股票和ETF的历史行情数据。 安装Akshare…

分布式--3--分布式事务

1 简介 事务在单系统中的表现&#xff1a;多次数据库操作用事务进行管理&#xff0c;来保证ACID原则。 但是如果各个模块都是单独独立出来的微服务&#xff0c;进行了分布式部署&#xff0c;单系统里的事务将不能保证各个数据库操作的一致性&#xff0c;因此就需要分布式事务来…

不同建模方式的介绍 RTL建模笔记(1)

说明&#xff1a;该专栏"RTL建模笔记"是《RTL Modeling with SystemVerilog for Simulation and Synthesis》的翻译&#xff1b;该笔记略过了第一章第一小节中背景介绍内容&#xff0c;以及第二小节前面部分的门级、RTL级建模介绍&#xff0c;对于后续学习不影响。 …

<13>-MySQL用户管理

目录 一&#xff0c;用户管理操作 1&#xff0c;创建用户 2&#xff0c;查询用户 3&#xff0c;修改密码 4&#xff0c;删除用户 二&#xff0c;数据库权限 1&#xff0c;用户授权 2&#xff0c;回收权限 一&#xff0c;用户管理操作 1&#xff0c;创建用户 --创建用户…

如何使用超低噪声电源提高AD 时钟电路质量,改善超声系统的图像质量

超声波技术是医疗诊断和其他应用中广泛使用的无创工具&#xff0c;已经从静态图像进化到动态图像&#xff0c;从黑白呈现变为彩色多普勒图像。这些重大进步主要是由于引入了数字超声技术。虽然这些进步提高了超声成像的有效性和通用性&#xff0c;但同样重要的是&#xff0c;这…

【解决方案】Kali 2022.3修复仓库密钥一键安装docker,docker compose

1、Kali 2022.3 2、一键安装docker&#xff0c;docker compose #!/bin/bashecho " 安全的Kali Docker安装脚本 "# 备份重要配置 cp /etc/apt/sources.list /etc/apt/sources.list.backup.$(date %Y%m%d)# 修复Kali仓库配置 echo "修复Kali仓库配置..." ca…

Transformer、RNN (循环神经网络) 和 CNN (卷积神经网络)的区别

我们来详细对比一下 Transformer、RNN (循环神经网络) 和 CNN (卷积神经网络) 这三种在深度学习中极其重要的架构&#xff0c;并通过具体例子说明它们的区别。 核心区别总结&#xff1a; 处理数据的方式&#xff1a; CNN: 专注于局部特征和空间/时间模式。通过卷积核在输入数据…

408第二季 - 组成原理 - 数据类型转换

这章内容会比较少 闲聊 如果题目说把8位改成4位&#xff0c;你保留低位就行了 这里保留的是0101 然后是有符号数和无符号数的转换 机器数就是二进制长什么样子 然后就是小数点是不参与存储的 然后简单看看代码 这是short就说明是有符号数 unsigned就是说明是无符号数 然后y…

让 Deepseek 写电器电费计算器(html版本)

以下是一个简单的电器电费计算器的HTML和CSS代码&#xff1a; <!DOCTYPE html> <html lang"zh-CN"> <head><meta charset"UTF-8"><meta name"viewport" content"widthdevice-width, initial-scale1.0">…

react_flow自定义节点、边——使用darg布局树状结构

文章目录 ⭐前言⭐引入react-flow⭐自定义节点nodeType⭐自定义边edgeType⭐添加节点⭐inscode代码块⭐结束 ⭐前言 大家好&#xff0c;我是yma16&#xff0c;本文分享 前端 ——react_flow自定义节点、边——使用darg布局树状结构。 自定义效果 可以自定义节点、边、线条流动…

word表格批量转excel,提取表格数据到excel

本文将带你一步步实现一个将 Word 中的表格内容批量提取并转换为 Excel 文件的自动化工具&#xff0c;适用于需要手动复制粘贴数据到excel的场景 假设我们有这样的表格在word中&#xff0c;图片世放在excel中便于截图&#xff0c;现在需要将表格中有颜色的数据提取到对应的exce…

day2课程

1.添加pinia到Vue项目 2.counter基础使用 3.getters和异步action 4.storeToRefs和调试 5.项目初始化和git管理 6.别名路径联想设置 7.elementsPlus自动按需导入配置 这个项目使用的是按需引入 1.安装包管理器 npm install element-plus --save 2.按需引入 npm install -D unp…

Vue3 + TypeScript + Element Plus 设置表格行背景颜色

技术要点&#xff1a; 1、使用 :row-class-name"setRowClassName" 设置表格行类名 2、不能同时使用 stripe 3、设置行类名的样式 应用效果&#xff1a; 同时使用 stripe 出来的效果&#xff1a; 参考代码&#xff1a; ReagentTable.vue <script setup lang&…