C++多线程学习(一):C++11 多线程快速入门
参考引用
- C++11 14 17 20 多线程从原理到线程池实战
- 代码运行环境:Visual Studio 2019
1. 为什么要用多线程
- 任务分解
- 耗时的操作,任务分解,实时响应
- 数据分解
- 充分利用多核CPU处理数据
- 数据流分解
- 读写分离,解耦合设计
2. 第一个子线程代码示例
- first_thread.cpp
#include <iostream> #include <thread>using namespace std;// 创建的子线程的入口函数 void ThreadMain() {// 获取子线程开始时刻的 ID 号cout << "begin sub thread ID " << this_thread::get_id() << endl;for (int i = 0; i < 5; i++) {cout << "in thread " << i << endl;// 子线程睡眠(释放)CPU 资源 1000msthis_thread::sleep_for(chrono::seconds(1)); }cout << "end sub thread ID " << this_thread::get_id() << endl; }// 主线程的入口函数 main() int main(int argc, char* argv[]) {cout << "main thread ID " << this_thread::get_id() << endl;// 线程创建启动thread th(ThreadMain);cout << "begin wait sub thread" << endl;// 阻塞等待子线程退出th.join();cout << "end wait sub thread" << endl;return 0; } - 控制台输出
main thread ID 21580 begin wait sub thread begin sub thread ID 22924 in thread 0 in thread 1 in thread 2 in thread 3 in thread 4 end sub thread ID 22924 end wait sub thread
3. std::thread 对象生命周期、线程等待和分离
-
thread_detach.cpp
#include <iostream> #include <thread>using namespace std;bool is_exit = false;void ThreadMain() {cout << "begin sub thread ID " << this_thread::get_id() << endl;for (int i = 0; i < 5; i++) {if (!is_exit)break;cout << "in thread " << i << endl;this_thread::sleep_for(chrono::seconds(1)); // 子线程睡眠(释放)CPU 资源 1000ms}cout << "end sub thread ID " << this_thread::get_id() << endl; }int main(int argc, char* argv[]) {{//thread th(ThreadMain); // 出错,thread 对象被销毁 子线程还在运行}{thread th(ThreadMain);th.detach(); // 子线程与主线程分离 守护线程(在后台运行)// 但存在一个问题:主线程退出后 子线程不一定退出}{thread th(ThreadMain);this_thread::sleep_for(chrono::seconds(1));//1000msis_exit = true; // 通知子线程退出cout << "主线程阻塞,等待子线程退出" << endl;th.join(); // 主线程阻塞,等待子线程退出cout << "子线程已经退出!" << endl;}getchar();return 0; } -
控制台输出
begin sub thread ID 25520 end sub thread ID 25520 begin sub thread ID 23324 end sub thread ID 23324 主线程阻塞,等待子线程退出 子线程已经退出!
4. 全局函数作为线程入口
-
thread_para.cpp
#include <iostream> #include <thread> #include <string>using namespace std;class Para { public:Para() {cout << "Create Para" << endl;}Para(const Para& p) { // 拷贝构造函数cout << "Copy Para" << endl; }~Para() {cout << "Drop Para" << endl;}string name; };void ThreadMain(int p1, float p2, string str, Para p4) {this_thread::sleep_for(100ms);cout << "ThreadMain " << p1 << " " << p2 << " " << str << " " << p4.name << endl; }int main(int argc, char* argv[]) {thread th;{float f1 = 12.1f;Para p;p.name = "test Para class";// 所有的参数做复制th = thread(ThreadMain, 101, f1, "test string para", p);}th.join();return 0; } -
控制台输出
Create Para Copy Para Drop Para Copy Para ThreadMain 101 12.1 test string para Drop Para Drop Para
5. 线程函数传递指针和引用
-
参数传递存在的问题
- 传递空间已经销毁
- 多线程共享访问一块空间
- 传递的指针变量的生命周期小于线程
-
thread_para.cpp
#include <thread>
#include <iostream>
#include <string>using namespace std;class Para {
public:Para() { cout << "Create Para" << endl; }Para(const Para& p) { cout << "Copy Para" << endl; }~Para() { cout << "Drop Para" << endl; }string name;
};void ThreadMain(int p1, float p2, string str, Para p4) {this_thread::sleep_for(100ms);cout << "ThreadMain " << p1 << " " << p2 << " " << str <<" "<<p4.name<< endl;
}void ThreadMainPtr(Para* p) {this_thread::sleep_for(100ms);cout << "ThreadMainPtr name = " << p->name << endl;
}void ThreadMainRef(Para& p) {this_thread::sleep_for(100ms);cout << "ThreadMainPtr name = " << p.name << endl;
}
int main(int argc, char* argv[]) {{// 传递引用Para p;p.name = "test ref";thread th(ThreadMainRef, ref(p));th.join();}getchar();{// 传递线程指针Para p;p.name = "test ThreadMainPtr name";thread th(ThreadMainPtr, &p); th.detach(); // 错误,线程访问的 p 空间会提前释放}getchar(); // Para 释放{ // 传递线程指针Para p;p.name = "test ThreadMainPtr name";thread th(ThreadMainPtr, &p);th.join();getchar();}thread th;{float f1 = 12.1f;Para p;p.name = "test Para class";// 所有的参数做复制th = thread(ThreadMain, 101, f1, "test string para", p);}th.join();return 0;
}
- 控制台输出
Create Para ThreadMainPtr name = test ref Drop Para
6. 成员函数作为线程入口–封装线程基类接口
-
XThread.h
- 封装线程基类接口
#pragma once#include <iostream> #include <thread>class XThread { public:virtual void Start() {is_exit_ = false;th_ = std::thread(&XThread::Main, this);}virtual void Stop() {is_exit_ = true;Wait();}virtual void Wait() {if (th_.joinable())th_.join();}bool is_exit() {return is_exit_;}private:virtual void Main() = 0; // 纯虚函数必须要在基类中实现std::thread th_;bool is_exit_ = false; // 符合谷歌代码风格,私有成员变量后缀加 _ }; -
thread_class.cpp
#include <iostream> #include <thread> #include <string> #include "XThread.h"using namespace std;/* class MyThread { public:// 入口线程函数void Main() {cout << "MyThread Main" << name << ": " << age;}string name;int age = 0; }; */class TestXThread : public XThread { public:void Main() override {cout << "TestXThread Main begin" << endl;while (!is_exit()) {this_thread::sleep_for(100ms);cout << "." << flush; // 添加 flush 是为了确保 . 正常输出}cout << "\nTestXThread Main end" << endl;}string name; };int main(int argc, char* argv[]) {TestXThread testth;testth.name = "TestXThread name ";testth.Start();this_thread::sleep_for(3s);testth.Stop();testth.Wait();getchar();/*MyThread myth;myth.name = "Test name";myth.age = 20;thread th(&MyThread::Main, &myth);th.join();*/return 0; } -
控制台输出
TestXThread Main begin ............................ TestXThread Main end
7. lambda 临时函数作为线程入口
-
lambda 函数基本格式
- [捕捉列表] (参数) mutable -> 返回值类型 {函数体}
-
thread_lambda.cpp
#include <iostream> #include <thread> #include <string>using namespace std;class TestLambda { public:void Start() {thread th([this]() {cout << "name = " << name << endl; });th.join();}string name = "Test Lambda"; };int main(int argc, char* argv[]) {thread th([](int i) {cout << "test lambda " << i << endl;}, 123);th.join();TestLambda test;test.Start();return 0; } -
控制台输出
test lambda 123 name = Test Lambda
8. call_once 多线程调用函数只进入一次
初始化函数可以在每一个类型的构造里都调用一遍,不用明确区分,代码可读性提升
-
call_once.cpp
#include <iostream> #include <thread> #include <string> #include <mutex>using namespace std;void SystemInit() {cout << "Call SystemInit" << endl; }void CallOnceSystemInit() {static std::once_flag flag; // 通过 flag 区分是否只调用一次std::call_once(flag, SystemInit); }int main(int argc, char* argv[]) {CallOnceSystemInit();CallOnceSystemInit();for (int i = 0; i < 3; i++) {thread th(CallOnceSystemInit);th.detach();}getchar();return 0; } -
控制台输出
Call SystemInit
相关文章:
C++多线程学习(一):C++11 多线程快速入门
参考引用 C11 14 17 20 多线程从原理到线程池实战代码运行环境:Visual Studio 2019 1. 为什么要用多线程 任务分解 耗时的操作,任务分解,实时响应 数据分解 充分利用多核CPU处理数据 数据流分解 读写分离,解耦合设计 2. 第一个…...
Linux系统之lsof命令的基本使用
Linux系统之lsof命令的基本使用 一、lsof命令的基本使用二、lsof命令的使用帮助2.1 lsof命令的help帮助信息2.2 lsof命令帮助解释 三、lsof的基本使用3.1 直接使用lsof命令3.2 查看某个进程打开的所有文件3.3 查看某个用户打开的所有文件3.4 查看某个文件被哪些进程打开3.5 查看…...
性能压力测试的优势与重要性
性能压力测试是软件开发过程中至关重要的一环,它通过模拟系统在极限条件下的运行,以评估系统在正常和异常负载下的表现。这种测试为确保软件系统的可靠性、稳定性和可伸缩性提供了关键信息。下面将探讨性能压力测试的优势以及为什么在软件开发中它具有不…...
AtCoder Beginner Contest 329 题解A~F
A - Spread 输入字符串,字符之间加上空格输出 B - Next 输出数组当中第二大的数 C - Count xxx 统计每个字符出现过的最长长度,再累加即可 #include<bits/stdc.h> #pragma GCC optimize("Ofast") #define INF 0x3f3f3f3f #define I…...
Windows网络「SSL错误问题」及解决方案
文章目录 问题方案 问题 当我们使用了神秘力量加持网络后,可能会和国内的镜像源网站的之间发生冲突,典型的有 Python 从网络中安装包,如执行 pip install pingouin 时,受网络影响导致无法完成安装的情况: pip config…...
python数据可视化
绘制简单的折线图 1.1json数据格式 JSON是一种轻量级的数据交互格式。可以按照JSON指定的格式去组织和封装数据,其本质上是一个带有特定格式的字符串。 主要功能:json就是一种在各个编程语言中流通的数据格式,负责不同编程语言中的数据传递…...
LV.12 D18 中断处理 学习笔记
一、ARM的异常处理机制及工程代码结构 1.1异常概念 处理器在正常执行程序的过程中可能会遇到一些不正常的事件发生 这时处理器就要将当前的程序暂停下来转而去处理这个异常的事件 异常事件处理完成之后再返回到被异常打断的点继续执行程序。 1.2异常处理机制 不同的处…...
蓝桥杯每日一题2023.11.19
题目描述 “蓝桥杯”练习系统 (lanqiao.cn) 题目分析 首先想到的方法为dfs去寻找每一个数,但发现会有超时 #include<bits/stdc.h> using namespace std; const int N 2e5 10; int n, cnt, a[N]; void dfs(int dep, int sum, int start) {if(dep 4){if(s…...
<b><strong>,<i><em>标签的区别
1. b标签和strong标签 b标签:仅仅是UI层面的加粗样式,并不具备HTML语义 strong标签:不仅是在UI层面的加粗样式,具备HTML语义,表示强调 2. i标签和em标签 i 标签:仅仅是UI层面的斜体样式,并不具备…...
c++中的特殊类设计
文章目录 1.请设计一个类,不能被拷贝2. 请设计一个类,只能在堆上创建对象3. 请设计一个类,只能在栈上创建对象4. 请设计一个类,不能被继承5. 请设计一个类,只能创建一个对象(单例模式) 1.请设计一个类,不能…...
开源更安全? yum源配置/rpm 什么是SSH?
文章目录 1.开放源码有利于系统安全2.yum源配置,这一篇就够了!(包括本地,网络,本地共享yum源)3.rpm包是什么4.SSH是什么意思?有什么功能? 1.开放源码有利于系统安全 开放源码有利于系统安全 2.yum源配置…...
庖丁解牛:NIO核心概念与机制详解 04 _ 分散和聚集
文章目录 Pre概述分散/聚集 I/O分散/聚集的应用聚集写入Code Pre 庖丁解牛:NIO核心概念与机制详解 01 庖丁解牛:NIO核心概念与机制详解 02 _ 缓冲区的细节实现 庖丁解牛:NIO核心概念与机制详解 03 _ 缓冲区分配、包装和分片 概述 分散/聚…...
Java读写Jar
Java提供了读写jar的类库Java.util.jar,Java获取解析jar包的工具类如下: import java.io.File; import java.io.IOException; import java.net.URL; import java.net.URLClassLoader; import java.util.Enumeration; import java.util.HashMap; import …...
【四元数简述】
w cos(theta/2) x ax * sin(theta/2) y ay * sin(theta/2) z az * sin(theta/2) 向量(x,y,z)是旋转轴 a 是任意正数 theta是旋转角度。 上面就是一个四元数表示旋转。 如何使用 空间中向量(1,2,3)扩展为(0,1,2,3&#…...
ClickHouse SQL 查询优化
1 单表查询 1.1 Prewhere替代where Prewhere和where语句的作用相同,用来过滤数据。不同之处在于prewhere只支持 *MergeTree 族系列引擎的表,首先会读取指定的列数据,来判断数据过滤,等待数据过滤之后再读取select 声明的列字段来补…...
「Verilog学习笔记」数据选择器实现逻辑电路
专栏前言 本专栏的内容主要是记录本人学习Verilog过程中的一些知识点,刷题网站用的是牛客网 分析 将变量A、B接入4选1数据选择器选择输入端S0 S1。将变量C分配在数据输入端。从表中可以看出输出L与变量C的关系。 当AB00时选通D0而此时L0,所以数据端D0接0…...
【Go入门】Web工作方式
【Go入门】 Web工作方式 我们平时浏览网页的时候,会打开浏览器,输入网址后按下回车键,然后就会显示出你想要浏览的内容。在这个看似简单的用户行为背后,到底隐藏了些什么呢? 对于普通的上网过程,系统其实是这样做的&…...
综述:目标检测二十年(机翻版)(未完
原文地址 20年来的目标检测:一项调查 摘要关键词一 介绍二 目标检测二十年A.一个目标检测的路线图1)里程碑:传统探测器Viola Jones探测器HOG检测器基于可变形零件的模型(DPM) 2)里程碑:基于CNN的两阶段探测器RCNNSPPN…...
quinn源码解析:QUIC数据包是如何发送的
quinn源码解析:QUIC数据包是如何发送的 简介QUIC协议中的概念endpoint(端点)connection(连接)Stream(流)Frame (帧) 发包过程解析SendStream::write_allConnectionDriverEndpointDriver 简介 q…...
scss的高级用法——循环
周末愉快呀!一起来学一点简单但非常有用的css小知识。 最近在一个项目中看到以下css class写法: 了解过tailwind css或者unocss的都知道,从命名就可以看出有以下样式: font-size: 30pxmargin-left: 5px;margin-top: 10px; 于是…...
UE5 学习系列(二)用户操作界面及介绍
这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…...
Vim 调用外部命令学习笔记
Vim 外部命令集成完全指南 文章目录 Vim 外部命令集成完全指南核心概念理解命令语法解析语法对比 常用外部命令详解文本排序与去重文本筛选与搜索高级 grep 搜索技巧文本替换与编辑字符处理高级文本处理编程语言处理其他实用命令 范围操作示例指定行范围处理复合命令示例 实用技…...
华为云AI开发平台ModelArts
华为云ModelArts:重塑AI开发流程的“智能引擎”与“创新加速器”! 在人工智能浪潮席卷全球的2025年,企业拥抱AI的意愿空前高涨,但技术门槛高、流程复杂、资源投入巨大的现实,却让许多创新构想止步于实验室。数据科学家…...
零门槛NAS搭建:WinNAS如何让普通电脑秒变私有云?
一、核心优势:专为Windows用户设计的极简NAS WinNAS由深圳耘想存储科技开发,是一款收费低廉但功能全面的Windows NAS工具,主打“无学习成本部署” 。与其他NAS软件相比,其优势在于: 无需硬件改造:将任意W…...
使用VSCode开发Django指南
使用VSCode开发Django指南 一、概述 Django 是一个高级 Python 框架,专为快速、安全和可扩展的 Web 开发而设计。Django 包含对 URL 路由、页面模板和数据处理的丰富支持。 本文将创建一个简单的 Django 应用,其中包含三个使用通用基本模板的页面。在此…...
Linux 文件类型,目录与路径,文件与目录管理
文件类型 后面的字符表示文件类型标志 普通文件:-(纯文本文件,二进制文件,数据格式文件) 如文本文件、图片、程序文件等。 目录文件:d(directory) 用来存放其他文件或子目录。 设备…...
【kafka】Golang实现分布式Masscan任务调度系统
要求: 输出两个程序,一个命令行程序(命令行参数用flag)和一个服务端程序。 命令行程序支持通过命令行参数配置下发IP或IP段、端口、扫描带宽,然后将消息推送到kafka里面。 服务端程序: 从kafka消费者接收…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
视频字幕质量评估的大规模细粒度基准
大家读完觉得有帮助记得关注和点赞!!! 摘要 视频字幕在文本到视频生成任务中起着至关重要的作用,因为它们的质量直接影响所生成视频的语义连贯性和视觉保真度。尽管大型视觉-语言模型(VLMs)在字幕生成方面…...
css的定位(position)详解:相对定位 绝对定位 固定定位
在 CSS 中,元素的定位通过 position 属性控制,共有 5 种定位模式:static(静态定位)、relative(相对定位)、absolute(绝对定位)、fixed(固定定位)和…...
