并发支持库(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

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

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

相关文章

Python函数嵌套与参数你学会了吗

如何在函数中调用其他函数&#xff0c;以及如何定义和使用函数参数。函数嵌套可以调用其他函数&#xff0c;参数列表用于封装函数中的未知数据&#xff0c;参数在函数调用时被替换。形参和实参数量需一致&#xff0c;但名字可以相同。 1.函数嵌套 一个函数中可以调用别的函数 …

Spring JdbcTemplate JpaRepository 数据库配置多个数据源连接、查询

所谓多数据源&#xff0c;就是一个项目中采用了不同数据库实例中的多个库&#xff0c;或者同一个数据库实例中多个不同的库。比如实现数据库读写分离、分库分表、备份等操作。   JdbcTemplate多数据源的配置是比较简单的&#xff0c;因为一个JdbcTemplate对应一个DataSource&…

分布式搜索引擎-elasticsearch基础

分布式搜索引擎-elasticsearch基础 1、什么是elasticsearch&#xff1f; elasticsearch是一款非常强大的开源搜索引擎&#xff0c;可以帮助我们从海量数据中快速找到需要的内容。 elasticsearch结合kibana、Logstash、Beats&#xff0c;也就是elastic stack&#xff08;ELK&a…

个人博客系列-后端项目-用户验证(5)

介绍 创建系统管理app&#xff0c;用于管理系统的用户&#xff0c;角色&#xff0c;权限&#xff0c;登录等功能&#xff0c;项目中将使用django-rest_framework进行用户认证和权限解析。这里将完成用户认证 用户验证 rest_framework.authentication模块中的认证类&#xff…

【C++】priority_queue和仿函数

priority_queue翻译过来就是优先队列&#xff0c;其实就是我们数据结构中的堆。堆这个东西之前也说过&#xff0c;它分为大根堆和小根堆&#xff0c;它的底层是一个类似数组的连续的空间&#xff0c;逻辑结构是一个完全二叉树&#xff0c;这个完全二叉树如果是小根堆的话父亲小…

Vue-03

Vue指令 v-bind 作用&#xff1a;动态设置html的标签属性&#xff08;src url title…&#xff09; 语法&#xff1a;v-bind:属性名"表达式" 举例代码如下&#xff1a; 实现效果如下&#xff1a; 案例&#xff1a;图片切换 实现代码如下&#xff1a; 实现的效果…

Redis面试问题纯享版

基础内容 1、简单介绍以下你了解的Redis 2、对比一下Redis和Memcache的异同&#xff1f; 3、为什么MySQL选用Redis作为缓存&#xff1f; 4、详细聊聊你对Redis各种数据类型的了解&#xff1f; 5、Redis中五种基本数据类型的底层数据结构是什么样的&#xff1f; Redis线程模型…

好物周刊#43:设计素材下载

https://yuque.com/cunyu1943 村雨遥的好物周刊&#xff0c;记录每周看到的有价值的信息&#xff0c;主要针对计算机领域&#xff0c;每周五发布。 一、项目 1. frp 一个专注于内网穿透的高性能的反向代理应用&#xff0c;支持 TCP、UDP、HTTP、HTTPS 等多种协议&#xff0c…

大华IPC网络摄像机如何保存视频

一、背景 通常网络相机&#xff08;IPC&#xff09;不会自带存储功能&#xff0c;需要接入录像机&#xff08;NVR&#xff09;进行保存。 其中NVR也分软件存储及硬件存储&#xff0c;这里不提&#xff0c;这边单独说FTP存储 二、配置前提 要配置FTP存储需要&#xff1a;①网络…

centos7迁移龙蜥anolis8.8-内网

一、离线仓库搭建 在内网搭建龙蜥镜像站 CentOS7下同步阿里云CentOS7镜像建本地yum仓库基本步骤 1、更新本地yum-关闭防火墙 # 将vim设置为黏贴模式&#xff0c;防止复制时自动缩进 echo "set paste" >> /root/.vimrc#设置防火墙为 Iptables 并设置空规则 s…

初识openGauss

一、openGauss 的介绍 openGauss 是一款全面友好开放&#xff0c;携手伙伴共同打造的企业级开源关系型数据库。openGauss 提供面向多核架构的极致性能、全链路的业务、数据安全、基于 AI 的调优和高效运维的能力。openGaus 深度融合华为在数据库领域多年的研发经验&#xff0c…

【python进阶篇】面向对象编程(1)

面向对象编程——Object Oriented Programming&#xff0c;简称OOP&#xff0c;是一种程序设计思想。OOP把对象作为程序的基本单元&#xff0c;一个对象包含了数据和操作数据的函数。 在Python中&#xff0c;所有数据类型都可以视为对象&#xff0c;当然也可以自定义对象。自定…

Stable Diffusion 模型分享:DucHaiten-AIart-SDXL(动漫、3D、逼真)

本文收录于《AI绘画从入门到精通》专栏&#xff0c;专栏总目录&#xff1a;点这里。 文章目录 模型介绍生成案例案例一案例二案例三案例四案例五案例六案例七案例八 下载地址 模型介绍 这是一个丰富多彩的 SDXL 模型&#xff0c;可以绘制动漫、3D、科幻、真实等类型的图片。 …

pyqt进入当前系统shell界面

在PyQt中可以使用QProcess类来运行外部命令并获取其输出。要进入当前系统的Shell界面&#xff0c;可以通过调用操作系统相关的命令来完成。 下面是一个示例代码&#xff0c;展示了如何在PyQt应用程序中打开当前系统的Shell界面&#xff1a; import sys from PyQt5.QtWidgets …

【开源物联网平台】FastBee认证方式和MQTT主题设计

&#x1f308; 个人主页&#xff1a;帐篷Li &#x1f525; 系列专栏&#xff1a;FastBee物联网开源项目 &#x1f4aa;&#x1f3fb; 专注于简单&#xff0c;易用&#xff0c;可拓展&#xff0c;低成本商业化的AIOT物联网解决方案 目录 一、接入步骤 1.1 设备认证 1.2 设备交…

Unity 动画(旧版-新版)

旧版 旧版-动画组件&#xff1a;Animation 窗口-动画 动画文件后缀: .anim 将制作后的动画拖动到Animation组件上 旧版的操作 using System.Collections; using System.Collections.Generic; using UnityEngine;public class c1 : MonoBehaviour {// Start is called before…

C语言学习--摩尔投票算法

目录 1.引入 2.摩尔投票算法 3.具体步骤 3.1抵消阶段 3.2检验过程 4.代码实现 5.总结 1.引入 今天做题看到一个解题思路真的看不懂&#xff0c;一艘才知道是这个算法。 int majorityElement(int* nums, int numsSize) { int notenums[0]; int count1; for(int i1;i<n…

MES+APS难度地狱级,搞定它就是劫后余生呀。

一、什么是MES和APS MES&#xff08;Manufacturing Execution System&#xff09;和APS&#xff08;Advanced Planning and Scheduling&#xff09;是两种在制造业中常用的软件系统&#xff0c;用于优化生产过程和提高生产效率。 MES是一种用于管理和监控制造过程的系统。它与…

稀碎从零算法笔记Day11-LeetCode:有效的字母异位词

题型&#xff1a;字符串、哈希表、排序 链接&#xff1a;242. 有效的字母异位词 - 力扣&#xff08;LeetCode&#xff09; 来源&#xff1a;LeetCode 题目描述 给定两个字符串 s 和 t &#xff0c;编写一个函数来判断 t 是否是 s 的字母异位词。 注意&#xff1a;若 s 和 …

SAP Parallel Accounting(平行分类账业务)配置及操作手册(超详细的说明和测试)

SAP Parallel Accounting(平行分类账业务)配置及操作手册 1、Overview 为了适应不同的会计准则&#xff0c;SAP在新总账中启用了多分类账&#xff0c;&#xff08;其作用简单来说就是&#xff0c;同时一笔记账&#xff0c;会产生多个账套的凭证。&#xff09;分类账可以对应一…