当前位置: 首页 > news >正文

《C++并发编程实战》笔记(一、二)

一、简介

抽象损失:对于实现某个功能时,可以使用高级工具,也可以直接使用底层工具。这两种方式运行的开销差异称为抽象损失。

二、线程管控

2.1 线程的基本控制

1. 创建线程

线程相关的管理函数和类在头文件:

#include <thread>

创建一个线程使用如下方法:

std::thread t(callable);
  • callable:线程函数,可以是任意的可调用对象
  • 线程对象创建后会立即启动线程运行

2. 控制线程的结束

线程启动后,必须显式指定线程结束的方式:

阻塞等待其结束(汇合),使用如下方法:

t.join();
  • 只要调用了join(),主线程会阻塞等待该线程执行结束,join()执行结束后,隶属于该线程的任何存储空间都会被清除,且线程对象不再关联到结束的线程
  • 成员函数t.joinable()返回线程对象t是否关联到某个线程,当join()执行结束后t.joinable()会返回false
  • 只有关联到某个线程的对象才能调用join()

让线程后台运行(分离),使用如下方法:

t.detach();
  • 线程对象必须关联某个线程(joinable()true时)才能调用detach,调用后线程的归属权和控制权都转移给C++运行时库,它独立于主线程继续运行,直至线程函数运行结束,且C++运行时库会保证线程退出后与之关联的资源都被正确回收
  • detach的线程不再关联实际的执行线程(joinable()会返回false),所以不可再调用join()

注意:如果线程对象销毁时都没有指定结束方式,则std::thread的析构函数会调用std::terminate()终止整个程序

3. 异常时保证线程正常结束

创建线程对象后,如果在指定线程结束方式前,因为执行其他代码造成了异常,可能会导致指定线程结束方式的代码被略过,从而导致程序终止。即:

void func() {try {// 线程 t 去执行 do_something() 函数std::thread t(do_something);// 此时如果发生异常等,下面的join可能无法被调用,退出func时程序会被中断do_other_thing();} catch (...) {throw;}t.join();return;
}

解决方法:

  1. 一种解决方法是保证在程序的所有执行路径都会指定线程结束方式
    void func() {try {std::thread t(do_something);do_other_thing();} catch (...) {// 保证一定会指定线程结束方式t.join();throw;}t.join();return;
    }
    
  2. 使用RAII方法,利用对象管理线程,在构造函数中创建线程,在析构函数中指定线程的结束方式
    class RaiiThreadGuard {public:explicit RaiiThreadGuard(std::thread &t) : t_(t) {} ~RaiiThreadGuard() {// 类对象离开作用域时一定会调用析构,保证一定会指定线程对象的结束方式t_.join();}// 将拷贝构造和拷贝赋值都定义为删除的,避免编译器优化造成重复调用析构RaiiThreadGuard(const RaiiThreadGuard &) = delete;RaiiThreadGuard& operator=(const RaiiThreadGuard &) = delete;private:std::thread& t_;
    };// main 函数中通过如下方式使用
    int main() {// 创建线程std::thread t(HelloFunction);// 使用 RAII 保证线程对象一定会调用 joinRaiiThreadGuard thread_guard(t);// 即使后续再执行其他代码造成退出作用域,编译器会保证执行 thread_guard 的析构指定线程的结束方式return 0;
    }

2.2 向线程函数传递参数

线程函数所需要的参数可以直接紧跟在std::thread的线程函数实参后:

  • 线程具有内部存储空间,线程函数的实参会先使用拷贝构造函数,将std::thread的实参复制到创建的线程;在创建好的线程中,新复制出来的实参被当成临时量,以右值形式传递给新线程中的线程函数
  • 根据参数的传递过程,如果线程函数包含非const引用形参,为避免在线程内执行时收到右值,需要通过std::refstd::thread传递实参(与std::bind函数的使用相同)
  • 类的非静态成员函数第一个参数是指向对象的隐式this指针,如果想在线程中执行某个成员函数,需要将对象地址传递给成员函数的隐式this指针
class TestClass {
public:/** @brief  默认构造函数 */TestClass(){std::cout << "TestClass default constructor." << std::endl;std::cout << "std::thread::id: " << std::this_thread::get_id() << std::endl;}/** @brief  拷贝构造函数 */TestClass(const TestClass& ohter) {std::cout << "TestClass copy constructor." << std::endl;std::cout << "std::thread::id: " << std::this_thread::get_id() << std::endl;}/** @brief  移动构造函数 */TestClass(TestClass&& ohter) {std::cout << "TestClass move constructor." << std::endl;std::cout << "std::thread::id: " << std::this_thread::get_id() << std::endl;}/** @brief  类的内部函数 */void InnerFunction() {std::cout << "TestClass Inner Function." << std::endl;std::cout << "std::thread::id: " << std::this_thread::get_id() << std::endl;}
};void func(int num, std::string &str, TestClass obj) {str += std::to_string(num);
}// main 函数
std::string str("The num: ");
TestClass test_class;
// 参数直接作为 std::thread 的后续参数传入
// 1. 对象会先调用拷贝构造复制到线程,再通过std::move()以右值复制给线程内的函数形参
// 2. 线程函数的引用形参要通过 std::ref() 传递
std::thread t(func, 3, std::ref(str), test_class);
t.join();
std::cout << str << std::endl;// 在线程中运行类的成员函数,需要将对象的地址传递给成员函数的隐式this指针
std::thread t2(&TestClass::InnerFunction, &test_class);
t2.join();/* 输出
TestClass default constructor.
std::thread::id: 140737348195264
TestClass copy constructor.
std::thread::id: 140737348195264
TestClass move constructor.
std::thread::id: 140737348179520
The num: 3
TestClass Inner Function.
std::thread::id: 140737348179520
*/

2.3 转移线程归属权

在某些情况下,如想要指定特定的函数等待线程结束,可能需要转移线程的归属权。

std::threadstd::unique类似,由于独占资源,其对象不能被复制,只支持移动

std::thread t1(some_function);
std::thread t2 = std::move(t1);

2.4 运行时确定线程数量

标准库的静态函数std::thread::hardware_concurrency()函数返回程序在执行时可以真正并发的线程数量:

  • 若信息无法获取,返回0
  • 否则返回支持并发的线程数

2.5 标识不同线程

每个线程都有一个唯一的ID,该ID是一个std::thread::id类型的变量:

  • 可以使用线程对象的std::thread::get_id()函数返回线程对象的ID
  • 在程序中可以使用std::this_thread::get_id()函数获取运行当前程序的线程ID
  • 默认构造创建的std::thread::id类型变量表示线程不存在

std::thread::joinable()函数会利用线程对象的ID确定返回值,即:

  • this.get_id() != std::thread::id() 则返回 true(判断当前线程ID和默认构造的线程ID类型变量是否相同)
  • 否则返回false(表示线程对象没有关联到任何线程,线程不存在)

相关文章:

《C++并发编程实战》笔记(一、二)

一、简介 抽象损失&#xff1a;对于实现某个功能时&#xff0c;可以使用高级工具&#xff0c;也可以直接使用底层工具。这两种方式运行的开销差异称为抽象损失。 二、线程管控 2.1 线程的基本控制 1. 创建线程 线程相关的管理函数和类在头文件&#xff1a; #include <…...

【日常bug记录】el-checkbox 绑定对象数组

版本说明 "vue": "2.6.10", "element-ui": "2.13.2", 这个写法很怪异哦&#xff0c;但确实管用。el-checkbox 绑定的 label 是双向绑定的值&#xff0c;也就是选中之后传到表单数据里面的值&#xff0c;一般设置为 id&#xff0c;然后…...

单元测试Mockito笔记

文章目录 单元测试Mockito1. 入门1.1 什么是Mockito1.2 优势1.3 原理 2. 使用2.0 环境准备2.1 Mock1) Mock对象创建2) 配置Mock对象的行为(打桩)3) 验证方法调用4) 参数匹配5) 静态方法 2.2 常用注解1) Mock2) BeforeEach 与 BeforeAfter3) InjectMocks4) Spy5) Captor6) RunWi…...

基于SpringBoot+VueJS+微信小程序技术的图书森林共享小程序设计与实现:7000字论文+源代码参考

博主介绍&#xff1a;硕士研究生&#xff0c;专注于信息化技术领域开发与管理&#xff0c;会使用java、标准c/c等开发语言&#xff0c;以及毕业项目实战✌ 从事基于java BS架构、CS架构、c/c 编程工作近16年&#xff0c;拥有近12年的管理工作经验&#xff0c;拥有较丰富的技术架…...

GitHub连接超时问题 Recv failure: Connection was reset

用手机热点WIF拉取git项目的时候&#xff0c;遇到Recv failure: Connection was reset问题。 解决办法 一、手动开启本地代理 二、在终端&#xff08;cmd&#xff09;输入命令 git config --global http.proxy http://127.0.0.1:7890 git config --global https.proxy https:…...

浅谈PostCSS

1. 背景 css的预处理器语言&#xff08;比如 sass&#xff0c; less&#xff0c; stylus&#xff09;的扩展性不好&#xff0c;你可以使用它们已有的功能&#xff0c;但如果想做扩展就没那么容易。 sass是很常用的css预处理器语言&#xff0c;在webpack中要使用它&#xff0c;…...

GCN、GIN

# 使用TuDataset 中的PROTEINS数据集。 # 里边有1113个蛋白质图&#xff0c;区分是否为酶&#xff0c;即二分类问题。# 导包 from torch_geometric.datasets import TUDataset from torch_geometric.data import DataLoader import torch import torch.nn as nn import torch.…...

Web控件进阶交互

Web控件进阶交互 测试时常需要模拟键盘或鼠标操作&#xff0c;可以用Python的ActionChains来模拟。ActionChains是Selenium提供的一个子类&#xff0c;用于生成和执行复杂的用户交互操作&#xff0c;允许将一系列操作链接在一起&#xff0c;然后一次性执行。 from selenium im…...

基于SpringBoot的校园疫情防控系统

你好&#xff0c;我是专注于计算机科学与技术的研究者。如果你对我的工作感兴趣或有任何问题&#xff0c;欢迎随时联系我。 开发语言&#xff1a;Java 数据库&#xff1a;MySQL 技术&#xff1a;SpringBoot框架&#xff0c;B/S架构 工具&#xff1a;Eclipse&#xff0c;Mav…...

elasticsearch 查询超10000的解决方案

前言 默认情况下&#xff0c;Elasticsearch集群中每个分片的搜索结果数量限制为10000。这是为了避免潜在的性能问题。 但是我们 在实际工作过程中时常会遇到 需要深度分页&#xff0c;以及查询批量数据更新的情况 问题&#xff1a;当请求form size >10000 时&#xff0c…...

SpringCloud集成kafka集群

目录 1.引入kafka依赖 2.在yml文件配置配置kafka连接 3.注入KafkaTemplate模版 4.创建kafka消息监听和消费端 5.搭建kafka集群 5.1 下载 kafka Apache KafkaApache Kafka: A Distributed Streaming Platform.https://kafka.apache.org/downloads.html 5.2 在config目录下做…...

Macos 远程登录 Ubuntu22.04 桌面

这里使用的桌面程序为 xfce, 而 gnome 桌面则测试失败。 1,安装 在ubuntu上&#xff0c;安装 vnc server与桌面程序xfce sudo apt install xfce4 xfce4-goodies tightvncserver 2&#xff0c;第一次启动和配置 $ tightvncserver :1 设置密码。 然后修改配置&#xff1a…...

第十届MathorCup高校数学建模挑战赛-A题:无车承运人平台线路定价问题

目录 摘 要 1 问题重述 1.1 研究背景 1.2 研究问题 2 符号说明与模型假设 2.1 符号说明 2.2 模型假设 3 问题一:模型建立与求解 3.1 问题分析与思路 3.2 模型建立 3.2.1 多因素回归模型 3.3 模型求解 3.3.1 数据预处理 3.3.2 重要度计算 4 问题二:模型建立与求…...

在分布式环境中,怎样保证 PostgreSQL 数据的一致性和完整性?

文章目录 在分布式环境中保证 PostgreSQL 数据的一致性和完整性一、数据一致性和完整性的重要性二、分布式环境对数据一致性和完整性的挑战&#xff08;一&#xff09;网络延迟和故障&#xff08;二&#xff09;并发操作&#xff08;三&#xff09;数据分区和复制 三、保证 Pos…...

RabbitMq如何保证消息的可靠性和稳定性

RabbitMq如何保证消息的可靠性和稳定性 rabbitMq不会百分之百让我们的消息安全被消费&#xff0c;但是rabbitMq提供了一些机制来保证我们的消息可以被安全的消费。 消息确认 消息者在成功处理消息后可以发送确认&#xff08;ACK&#xff09;给rabbitMq&#xff0c;通知消息已…...

druid(德鲁伊)数据线程池连接MySQL数据库

文章目录 1、druid连接MySQL2、编写JDBCUtils 工具类 1、druid连接MySQL 初学JDBC时&#xff0c;连接数据库是先建立连接&#xff0c;用完直接关闭。这就需要不断的创建和销毁连接&#xff0c;会消耗系统的资源。 借鉴线程池的思想&#xff0c;数据连接池就这么被设计出来了。…...

观察者模式的实现

引言&#xff1a;观察者模式——程序中的“通信兵” 在现代战争中&#xff0c;通信是胜利的关键。信息力以网络、数据、算法、算力等为底层支撑&#xff0c;在现代战争中不断推动感知、决策、指控等各环节产生量变与质变。在软件架构中&#xff0c;观察者模式扮演着类似的角色…...

Eureka: Netflix开源的服务发现框架

在微服务架构中&#xff0c;服务发现是一个关键组件&#xff0c;它允许服务实例之间相互发现并进行通信。Eureka是由Netflix开源的服务发现框架&#xff0c;它是Spring Cloud体系中的核心组件之一。Eureka提供了服务注册与发现的功能&#xff0c;支持区域感知和自我保护机制&am…...

go-基准测试

基准测试 Demo // fib_test.go package mainimport "testing"func BenchmarkFib(b *testing.B) {for n : 0; n < b.N; n {fib(30) // run fib(30) b.N times} }func fib(n int) int {if n 0 || n 1 {return n}return fib(n-2) fib(n-1) }benchmark 和普通的单…...

线性代数|机器学习-P23梯度下降

文章目录 1. 梯度下降[线搜索方法]1.1 线搜索方法&#xff0c;运用一阶导数信息1.2 经典牛顿方法&#xff0c;运用二阶导数信息 2. hessian矩阵和凸函数2.1 实对称矩阵函数求导2.2. 线性函数求导 3. 无约束条件下的最值问题4. 正则化4.1 定义4.2 性质 5. 回溯线性搜索法 1. 梯度…...

19c补丁后oracle属主变化,导致不能识别磁盘组

补丁后服务器重启&#xff0c;数据库再次无法启动 ORA01017: invalid username/password; logon denied Oracle 19c 在打上 19.23 或以上补丁版本后&#xff0c;存在与用户组权限相关的问题。具体表现为&#xff0c;Oracle 实例的运行用户&#xff08;oracle&#xff09;和集…...

UE5 学习系列(三)创建和移动物体

这篇博客是该系列的第三篇&#xff0c;是在之前两篇博客的基础上展开&#xff0c;主要介绍如何在操作界面中创建和拖动物体&#xff0c;这篇博客跟随的视频链接如下&#xff1a; B 站视频&#xff1a;s03-创建和移动物体 如果你不打算开之前的博客并且对UE5 比较熟的话按照以…...

工业自动化时代的精准装配革新:迁移科技3D视觉系统如何重塑机器人定位装配

AI3D视觉的工业赋能者 迁移科技成立于2017年&#xff0c;作为行业领先的3D工业相机及视觉系统供应商&#xff0c;累计完成数亿元融资。其核心技术覆盖硬件设计、算法优化及软件集成&#xff0c;通过稳定、易用、高回报的AI3D视觉系统&#xff0c;为汽车、新能源、金属制造等行…...

第 86 场周赛:矩阵中的幻方、钥匙和房间、将数组拆分成斐波那契序列、猜猜这个单词

Q1、[中等] 矩阵中的幻方 1、题目描述 3 x 3 的幻方是一个填充有 从 1 到 9 的不同数字的 3 x 3 矩阵&#xff0c;其中每行&#xff0c;每列以及两条对角线上的各数之和都相等。 给定一个由整数组成的row x col 的 grid&#xff0c;其中有多少个 3 3 的 “幻方” 子矩阵&am…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

Yolov8 目标检测蒸馏学习记录

yolov8系列模型蒸馏基本流程&#xff0c;代码下载&#xff1a;这里本人提交了一个demo:djdll/Yolov8_Distillation: Yolov8轻量化_蒸馏代码实现 在轻量化模型设计中&#xff0c;**知识蒸馏&#xff08;Knowledge Distillation&#xff09;**被广泛应用&#xff0c;作为提升模型…...

人机融合智能 | “人智交互”跨学科新领域

本文系统地提出基于“以人为中心AI(HCAI)”理念的人-人工智能交互(人智交互)这一跨学科新领域及框架,定义人智交互领域的理念、基本理论和关键问题、方法、开发流程和参与团队等,阐述提出人智交互新领域的意义。然后,提出人智交互研究的三种新范式取向以及它们的意义。最后,总结…...

Netty从入门到进阶(二)

二、Netty入门 1. 概述 1.1 Netty是什么 Netty is an asynchronous event-driven network application framework for rapid development of maintainable high performance protocol servers & clients. Netty是一个异步的、基于事件驱动的网络应用框架&#xff0c;用于…...

在鸿蒙HarmonyOS 5中使用DevEco Studio实现企业微信功能

1. 开发环境准备 ​​安装DevEco Studio 3.1​​&#xff1a; 从华为开发者官网下载最新版DevEco Studio安装HarmonyOS 5.0 SDK ​​项目配置​​&#xff1a; // module.json5 {"module": {"requestPermissions": [{"name": "ohos.permis…...

从面试角度回答Android中ContentProvider启动原理

Android中ContentProvider原理的面试角度解析&#xff0c;分为​​已启动​​和​​未启动​​两种场景&#xff1a; 一、ContentProvider已启动的情况 1. ​​核心流程​​ ​​触发条件​​&#xff1a;当其他组件&#xff08;如Activity、Service&#xff09;通过ContentR…...