并发支持库(1)-线程
线程允许多个程序任务在统一时间执行,不同的线程可以共享内存空间,每个线程也有自己的栈空间。
线程类
thread
类thread表示单个执行线程。线程在thread构造对象时开始执行。每个thread对象表示唯一的一个线程,thread不支持复制构造和复制赋值函数。
构造函数
默认的构造函数构造一个不表示任何线程的thread对象:
thread() noexcept;
构造函数可以传入一个函数并关联一个执行线程,构造完成后函数将在该线程上开始运行:
template< class F, class... Args >
explicit thread( F&& f, Args&&... args );
代码示例:
auto func = [](int index)
{for (int i = 0; i < 15; ++i){std::cout << index;std::this_thread::sleep_for(std::chrono::milliseconds(10));}
};std::thread t1(func, 1);
std::thread t2(func, 2);
t1.join();
t2.join();
std::cout << std::endl;
t1和t2分别在两个线程上同时执行,打印出来的1和2可能是交错的,可能的输出结果:
122121121212121212212121212121
析构函数
销毁thread对象时,必须合并或者分离底层线程,否则会调用std::terminate导致程序崩溃。其内部实现大致为:
~thread() noexcept
{if (joinable()) {terminate();}
}
赋值函数
thread只支持移动赋值函数,移动后线程的所有权被转交,原thread对象不再表示任何线程。
joinable
检查线程是否可合并,如果thread代表的线程是活跃的,那么joinable返回true。代码示例:
std::cout << std::boolalpha;std::thread t;
std::cout << "t joinable: " << t.joinable() << std::endl;
t = std::thread([](){});
std::cout << "t joinable: " << t.joinable() << std::endl;
t.join();
std::cout << "t joinable: " << t.joinable() << std::endl;
输出结果:
t joinable: false
t joinable: true
t joinable: false
get_id
获取线程的id。代码示例:
std::thread t1;
std::thread t2 = std::thread([](){});
std::thread t3 = std::thread([](){});std::cout << "t1 id: " << t1.get_id() << std::endl;
std::cout << "t2 id: " << t2.get_id() << std::endl;
std::cout << "t3 id: " << t3.get_id() << std::endl;t2.join();
t3.join();
输出结果:
t1 id: 0
t2 id: 97068
t3 id: 73212
native_handle
获取底层实现的线程句柄。代码示例:
std::thread t = std::thread([](){});std::thread::native_handle_type handle = t.native_handle();
std::cout << "native handle: " << handle << std::endl;
t.join();
输出结果:
native handle: 00000000000000A8
hardware_concurrency
返回系统的逻辑处理线程数。代码示例:
auto num = std::thread::hardware_concurrency();
std::cout << "hardware concurrency: " << num << std::endl;
可能的输出结果:
hardware concurrency: 8
join
阻塞thread代表的线程直到其执行结束。代码示例:
auto Func = []()
{std::cout << "t thread" << std::endl;std::this_thread::sleep_for(std::chrono::seconds(1));
};std::thread t(Func);
t.join();
std::cout << "Done " << std::endl;
输出结果:
t thread
Done
detach
将thread管理的线程从thread中分离,thread不再代表任何线程。代码示例:
auto Func = []()
{std::this_thread::sleep_for(std::chrono::seconds(1));std::cout << "Func about to end" << std::endl;
};std::thread t(Func);
t.detach();
std::cout << "t detach" << std::endl;
std::this_thread::sleep_for(std::chrono::seconds(5));
输出结果:
t detach
Func about to end
swap、std::swap
交换两个thread管理的线程。
jthread
和thread类似,jthread管理一个执行线程。不同的是,当jthread析构时会自动合并线程。jthread内部还有一个stop_source成员(stop_source包含stop_token对象),jthread可以接受一个用stop_token作为首参数的函数用于执行线程访问,jthread有一个request_stop接口用于修改stop_token的状态,这允许执行函数根据stop_token的状态来决定是否终止函数运行。
构造函数
构造一个jthread对象并关联一个执行线程(默认构造函数不关联任何线程)。代码示例:
auto func = [](int index)
{for (int i = 0; i < 15; ++i){std::cout << index;std::this_thread::sleep_for(std::chrono::milliseconds(10));}
};std::jthread t1(func, 1);
std::jthread t2(func, 2);
t1.join();
t2.join();
std::cout << std::endl;
输出结果:
122112121212122121211212211212
析构函数
jthread对象析构时,会尝试合并其管理的执行线程,其内部实现大致为:
~jthread()
{if (joinable()) {request_stop();join();}
}
赋值函数
jthread只支持移动赋值函数,移动后线程的所有权被转交,原jthread对象不再表示任何线程。
joinable
检查线程是否可合并,如果thread代表的线程是活跃的,那么joinable返回true。
get_id
获取线程的id。
native_handle
获取底层实现的线程句柄。
hardware_concurrency
返回系统的逻辑处理线程数。
join
阻塞thread代表的线程直到其执行结束。
detach
将jthread管理的线程从jthread中分离,jthread不再代表任何线程。
swap、std::swap
交换两个jthread管理的线程。
停止记号处理
jthread提供了get_stop_source、get_stop_token用于获取stop_source和stop_token对象,requset_stop接口用于修改stop_token状态为停止,jthread关联的执行函数可以通过其第一个参数stop_token用于其状态。代码示例:
auto Func = [](std::stop_token token)
{for (int i = 0; i < 10; ++i){if (token.stop_requested()){std::cout << i << " token stop_requested true" << std::endl;}else{std::cout << i << " token stop_requested false" << std::endl;}std::this_thread::sleep_for(std::chrono::milliseconds(100));}
};std::jthread t(Func);
std::this_thread::sleep_for(std::chrono::milliseconds(350));
t.request_stop();
可能的输出结果:
0 token stop_requested false
1 token stop_requested false
2 token stop_requested false
3 token stop_requested false
4 token stop_requested true
5 token stop_requested true
6 token stop_requested true
7 token stop_requested true
8 token stop_requested true
9 token stop_requested true
注意最后一行代码
t.request_stop();
不是必须的,因为对象 t 在析构时也会调用request_stop函数。
当前线程管理函数
yield
重调度线程的执行,允许其他线程运行。具体效果依赖于编译器的实现。
get_id
返回当前线程的id。代码示例:
auto Func = []()
{std::cout << "thread id: " << std::this_thread::get_id() << std::endl;
};std::thread t1(Func);
std::thread t2(Func);
Func();t1.join();
t2.join();
输出结果:
thread id: 22388
thread id: 79692
thread id: 85280
sleep_for
阻塞当前线程一段时间。代码示例:
auto t1 = std::chrono::system_clock::now();
std::this_thread::sleep_for(std::chrono::milliseconds(300));
auto t2 = std::chrono::system_clock::now();
std::chrono::duration<double, std::milli> time = t2 - t1;
std::cout << "time pass: " << time.count() << std::endl;
可能的输出结果:
time pass: 302.473
sleep_util
阻塞当前线程到指定的时间点。代码示例:
auto t1 = std::chrono::system_clock::now();
std::this_thread::sleep_until(t1 + std::chrono::milliseconds(400));
auto t2 = std::chrono::system_clock::now();
std::chrono::duration<double, std::milli> time = t2 - t1;
std::cout << "time pass: " << time.count() << std::endl;
可能的输出结果:
time pass: 400.504
相关文章:
并发支持库(1)-线程
线程允许多个程序任务在统一时间执行,不同的线程可以共享内存空间,每个线程也有自己的栈空间。 线程类 thread 类thread表示单个执行线程。线程在thread构造对象时开始执行。每个thread对象表示唯一的一个线程,thread不支持复制构造和复制…...
2024年最新阿里云服务器地域选择方法,以及可用区说明
阿里云服务器地域和可用区怎么选择?地域是指云服务器所在物理数据中心的位置,地域选择就近选择,访客距离地域所在城市越近网络延迟越低,速度就越快;可用区是指同一个地域下,网络和电力相互独立的区域&#…...
Frida实战:Java、Native、SO层面的Hook与主动调用详解
引言 Frida是一款强大的动态代码插桩工具,支持对Android和iOS应用进行实时调试和注入。本文将通过实例详细解析如何在Frida中实现对Java层、Native层(JNI)以及.so库内函数的Hook与主动调用。 一、Hook Java层函数 首先,我们展示…...
Codeforces Round 883 (Div. 3)(集训队加训1)
A.如果钉子与地面距离大于绳子的长度就必须剪 #include<bits/stdc.h> #define eps 1e-5 #define INF 1e9 using namespace std; typedef long long ll; const int N 2e6 9; int a[N],b[N],cl[N]; void Lan(){int n;cin>>n;for(int i1;i<n;i){cin>>a[i]…...
自封装 bind 方法(二)
因为 bind 的使用方法是 某函数.bind(某对象,...剩余参数) 所以需要在 Function.prototype 上进行编程将传递的参数中的某对象和剩余参数使用 apply 的方式在一个回调函数中执行即可要在第一层获取到被绑定函数的 this,因为要拿到那个函数用 apply /***…...
vcomp140.dll丢失如何修复,5种修复方法轻松搞定vcomp140.dll问题
vcomp140.dll文件的丢失可能会引发一系列系统运行与软件功能上的问题。具体来说,这个动态链接库文件是Visual C Redistributable的一部分,对于许多基于此环境开发的应用程序至关重要。一旦缺失,可能会导致部分应用程序无法正常启动或运行&…...
计算机视觉(Computer Vision)和机器视觉(Machine Vision)
举例说明计算机视觉(CV)技术的优势和挑战 计算机视觉(CV)技术是一种使用计算机科学和机器学习方法来解释、分析和理解图像和视频的技术。它的优势和挑战如下: 优势: 高效性:CV技术可以快速处…...
国内用ChatGPT可以吗
PS: 无限次数,无需魔法,登录即可使用,网页打开下面 tj4.mnsfdx.net 点击跳转链接 国内用ChatGPT可以吗?简单来说,是可以的,国内可以使用ChatGPT。ChatGPT是一款实体机器翻译工具,也是一种人工智能技术&…...
数据分析-Pandas两种分组箱线图比较
数据分析-Pandas两种分组箱线图比较 数据分析和处理中,难免会遇到各种数据,那么数据呈现怎样的规律呢?不管金融数据,风控数据,营销数据等等,莫不如此。如何通过图示展示数据的规律? 数据表&am…...
Mac版2024 CleanMyMac X 4.14.6 核心功能详解以及永久下载和激活入口
CleanMyMac 是 macOS 上久负盛名的系统清理工具,2018 年,里程碑式版本 CleanMyMac X 正式发布。不仅仅是命名上的变化,焕然一新的 UI、流畅的动画也让它显得更加精致。新增的系统优化、软件更新等功能,使得在日常使用 macOS 时有了…...
Java引用传递及基本应用
在 Java 中,传递参数的方式主要有两种:值传递(传递的是对象的引用值)和引用传递。本教程将重点介绍 Java 中的引用传递以及其基本应用。 1. 引用传递概念 在 Java 中,所有的方法参数都是通过值传递的。对于对象类型的…...
低代码测试自动化
每个企业都希望将产品快速推向市场。虽然低代码无代码测试自动化可以帮助组织实现这一目标,但测试人员必须牢记几件事,才能通过低代码无代码来推进他们的组织。 低代码测试自动化的重要性是什么? 低代码测试自动化加速了测试生命周期。借助简…...
Linux 文件操作命令
1 文件与目录操作 cd /home 进入 ‘/home’ 目录 cd .. 返回上一级目录cd ../.. 返回上两级目录cd - 返回上次所在目录cp file1 file2 将file1复制为file2cp -a dir1 dir2 复制一个目录 cp -a /tmp/dir1 . 复制一个…...
机器学习-面经(part8、贝叶斯和其他知识点)
机器学习面经其他系列 机器学习面经系列的其他部分如下所示: 机器学习-面经(part1)-初步说明 机器学习-面经(part2)-交叉验证、超参数优化、评价指标等内容 机器学习-面经(part3)-正则化、特征工程面试问题与解答合集机器学习-面经(part4)-决策树共5000字的面试问…...
图数据库 之 Neo4j - 应用场景3 - 知识图谱(8)
背景 知识图谱的复杂性:知识图谱通常包含大量的实体、关系和属性,以及它们之间的复杂关联。传统的关系型数据库在处理这种复杂性时可能面临性能和灵活性的挑战。 图数据库的优势:图数据库是一种专门用于存储和处理图结构数据的数据库。它们使用节点和边来表示实体和关系,并…...
redis 性能优化三
前言 如果Redis 没有执行大量的慢查询,同时也没有删除大量的过期的keys,那么我们该怎么办呢?那么我们是不是就应该关注影响性能的其他机制了,也就是文件系统和操作系统了。 Redis 会把数据持久化到磁盘,这个过程依赖文件系统来完…...
Python用Tkinter实现圆的半径 面积 周长 知一求二程序
Python用Tkinter实现圆的半径 面积 周长 知一求二程序 import tkinter as tk from tkinter import messagebox from tkinter import *app tk.Tk() app.title(圆的半径 面积 周长 知一求二程序) app.geometry(425x125)label1 tk.Label(app, text"半径") label2 tk.…...
电源环路补偿的目标是避免产生正反馈
在一般的认识中,进行电源环路设计的目的是保证电源输出端的电压稳定,在误差信号传入系统时,系统进行负反馈调节,矫正干扰信号带来的误差量。 那么,为什么要设置成这样,不稳定会有什么后果等等,…...
SSM+MySQL替换探索 openGauss对比postgresql12
SSM 介绍 SSM(SpringSpringMVCMyBatis)框架集由 Spring、MyBatis 两个开源框架整合而成(SpringMVC 是 Spring 中的部分内容),常作为数据源较简单的 web 项目的框架。 Spring Spring 就像是整个项目中装配 bean 的大…...
XGboost的整理
XGboost(extreme gradient boosting):高效实现了GBDT算法并进行了算法和工程上的许多改进。 XGboost的思路: 目标:建立k个回归树,使得树群的预测尽量接近真实值(准确率)而且有尽量大的泛化能力…...
ubuntu搭建nfs服务centos挂载访问
在Ubuntu上设置NFS服务器 在Ubuntu上,你可以使用apt包管理器来安装NFS服务器。打开终端并运行: sudo apt update sudo apt install nfs-kernel-server创建共享目录 创建一个目录用于共享,例如/shared: sudo mkdir /shared sud…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
解决本地部署 SmolVLM2 大语言模型运行 flash-attn 报错
出现的问题 安装 flash-attn 会一直卡在 build 那一步或者运行报错 解决办法 是因为你安装的 flash-attn 版本没有对应上,所以报错,到 https://github.com/Dao-AILab/flash-attention/releases 下载对应版本,cu、torch、cp 的版本一定要对…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
NLP学习路线图(二十三):长短期记忆网络(LSTM)
在自然语言处理(NLP)领域,我们时刻面临着处理序列数据的核心挑战。无论是理解句子的结构、分析文本的情感,还是实现语言的翻译,都需要模型能够捕捉词语之间依时序产生的复杂依赖关系。传统的神经网络结构在处理这种序列依赖时显得力不从心,而循环神经网络(RNN) 曾被视为…...
【论文阅读28】-CNN-BiLSTM-Attention-(2024)
本文把滑坡位移序列拆开、筛优质因子,再用 CNN-BiLSTM-Attention 来动态预测每个子序列,最后重构出总位移,预测效果超越传统模型。 文章目录 1 引言2 方法2.1 位移时间序列加性模型2.2 变分模态分解 (VMD) 具体步骤2.3.1 样本熵(S…...
根据万维钢·精英日课6的内容,使用AI(2025)可以参考以下方法:
根据万维钢精英日课6的内容,使用AI(2025)可以参考以下方法: 四个洞见 模型已经比人聪明:以ChatGPT o3为代表的AI非常强大,能运用高级理论解释道理、引用最新学术论文,生成对顶尖科学家都有用的…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
使用LangGraph和LangSmith构建多智能体人工智能系统
现在,通过组合几个较小的子智能体来创建一个强大的人工智能智能体正成为一种趋势。但这也带来了一些挑战,比如减少幻觉、管理对话流程、在测试期间留意智能体的工作方式、允许人工介入以及评估其性能。你需要进行大量的反复试验。 在这篇博客〔原作者&a…...
Vue ③-生命周期 || 脚手架
生命周期 思考:什么时候可以发送初始化渲染请求?(越早越好) 什么时候可以开始操作dom?(至少dom得渲染出来) Vue生命周期: 一个Vue实例从 创建 到 销毁 的整个过程。 生命周期四个…...
