C++11:多线程编程
目录
- 线程库基本用法
- 创建线程
- 给线程传递参数
- 线程分离
- 常见数据未定义错误
- 传递指针或引用指向局部变量的问题
- 传递指针或引用指向已释放的内存的问题
- 类成员函数作为入口函数,类对象被提前释放
- 智能指针来解决该问题
- 入口函数为类的私有成员函数
- 互斥量
- 死锁
- lock_guard与unique_lock
- unique_lock
- std::call_once(单例模式)
- condition_variable(生产者与消费者模型)
- C++11实现跨平台线程池
- 异步开发
- future
- packaged_task
- promise
- 原子操作
- std::atmoic
- load()
- store()
进程是正在运行的程序
线程就是进程中的进程
线程库基本用法
创建线程
但是运行时发现并没有打印helloworld,因为主线程运行完了,子线程还没有创建好,所以需要等待子线程运行完,主线程再退出。
join是阻塞的,会阻塞主线程的运行
给线程传递参数
直接在thread的函数后面,有点像绑定器
线程分离
主线程不用等待子线程结束,可以先结束。
常见数据未定义错误
这段会报错
而且也不能传a
因为线程函数传参是值传递,即使在函数里面用了引用,线程函数拿到的还是复制该引用指向的数据值类型。而且不能把右值传递给左值引用。
所以传递的左右值引用要统一
确实不加引用的话,能运行
传递指针或引用指向局部变量的问题
这边int a是不能放在函数里面的,因为在函数内部a是局部的,当出了test后,a就自动销毁了,地址也没了,所以就引用不到。要把a设为全局变量。
C++11的thread默认会复制传递的参数,因此直接传递引用会导致引用被复制,无法修改原始变量。
传递指针或引用指向已释放的内存的问题
ptr是指向1的一个指针,按道理应该是输出1,但是输出了0,说明这个程序已经是错了
这个错误的原因是,在子线程去打印这个1的时候,主线程可能已经完成释放指针了,那么指针指向的内容会是任何数(野指针)
改进方法,可以主线程加个sleep再释放。
主线程和子线程各跑各的,子程序想要访问某个地址,某块内存,但是主线程已经释放掉了。
那除了sleep还有什么方法
类成员函数作为入口函数,类对象被提前释放
和上面一样,成员函数在子线程运行,想要访问某个资源的时候,被主线程释放掉了,就取不到资源了
std::thread t(&MyClass::func,&obj)
智能指针来解决该问题
在解决类的释放问题的时候,肯定不能用sleep,因为你也不知道程序要跑多少秒,我们希望程序能够自动地在调用完类对象之后,自动销毁类对象。
那么可以用智能指针来创建对象。这样就不用手写delete,然后又有类对象被提前释放,或者说忘记写delete导致内存泄露的问题。
#include <iostream>
#include <thread>
#include <memory>std::thread t;class A{
public:void foo(){std::cout<<"Hello"<<std::endl;}
};int main()
{std::shared_ptr<A> a=std::make_shared<A>();std::thread t(&A::foo,a);t.join();return 0;
}
为什么这里传入a不需要加引用了,因为a本身就是一个指针了
入口函数为类的私有成员函数
当foo为私有成员函数时,在类外部使用类作用域是调用不到的。
如何解决?
使用友元
加一个声明就可以了
互斥量
解决数据共享产生的问题
预期a加的结果为2000000,但是没有到,因为两个线程同时去拿,本应该加2的可能就只能加1了。
在写操作之前对他加锁,写完了之后解锁
如果多线程程序每一次的运行结果和单线程运行的结果始终是一样的,那么你的线程就是安全的。
死锁
一直在运行等待,出现死锁,因为t1需要m2的锁,t2需要m1的锁
改变顺序就可以了
互斥量多的时候很容易产生死锁
lock_guard与unique_lock
加完锁一定要解锁,这是很严重的一个错误
lock_guard,当构造函数被调用时,该互斥量自动锁定,析构函数被调用时,该互斥量自动解锁。lock_guard对象不能复制或移动,只能在局部作用域中使用。
lock_guard就不用使用加锁和解锁操作
为这个对象传入一个锁类型
lock_guard源码中,就是构造函数和析构函数自动加锁和解锁
unique_lock
延迟加锁、条件变量、超时等
unique_lock在lock_guard基础上多了一个延迟加锁的功能
如果5s之后还没有加锁,那么就退出
但是这样是报错的,因为给对象传入的类型需要是时间锁
2s内没拿到锁那就直接结束返回了。
正常的加锁是拿不到锁一直等,所以有死锁的情况,那么我这里超时了直接返回。
正常情况是返回4
std::call_once(单例模式)
单例设计模式确保某个类只能创建一个实例,单例实例是全局唯一的,因此在多线程环境中使用单例模式时,需要考虑线程安全的问题。
比如说日志类,全局只需要一个日志对象,就可以完成所有的打印操作了
单例模式就是要将构造函数私有化,这样才能阻止外部直接创建类对象。
懒汉模式,就是一个懒汉只有在需要的时候才起床一样,只有需要的时候才实例化,饿汉模式,就像饿汉遇到食物一样急不可耐,类加载完后就完成了对象就创建完成了。
为什么要使用call_once?
当多线程进来之后,单例就调用了两次,违反原则了
call_once能够确保某个函数只会被调用一次
静态成员函数没有this指针这个形参,所以无法操作非静态成员。
call_once调用函数,需要一个函数,一个onceflag
condition_variable(生产者与消费者模型)
生产者不停去安排任务,消费者不停地去取任务,消费者有很多个(也可以理解为,生产者为一个老板,消费者为很多个打工人)。
条件变量需要和互斥锁一起使用,
#include <iostream>
#include <thread>
#include <memory>
#include <mutex>
#include <windows.h>
#include <string>
#include <condition_variable>
#include <queue>std::queue<int>g_queue;
std::condition_variable g_cv;
std::mutex mtx;
void Producer(){for(int i=0;i<10;i++){{std::unique_lock<std::mutex> lock(mtx);g_queue.push(i);//通知消费者来取任务g_cv.notify_one();std::cout<<"task:"<<i<<std::endl;}std::this_thread::sleep_for(std::chrono::microseconds(100));}
}void Consumer(){while(1){std::unique_lock<std::mutex> lock(mtx);bool isempty=g_queue.empty();//如果队列为空,就要等待g_cv.wait(lock,[](){return !g_queue.empty();});int value=g_queue.front();g_queue.pop();std::cout<<"consumer"<<value<<std::endl;}
}int main()
{std::thread t1(Producer);std::thread t2(Consumer);t1.join();t2.join();return 0;
}
C++11实现跨平台线程池
异步开发
future
#include <iostream>
#include <thread>
#include <memory>
#include <mutex>
#include <windows.h>
#include <string>
#include <condition_variable>
#include <queue>
#include <atomic>
#include <future>
using namespace std;int func(){int i=0;for(i=0;i<1000;i++){i++;}return i;
}int main()
{std::future<int> future_result=std::async(std::launch::async,func);cout<<func()<<endl;cout<<future_result.get()<<endl;return 0;
}
有点相当于又开了个线程去执行函数,然后结果保存在future_result里面。
只不过这个线程不需要自己手动去创建
packaged_task
task只是把函数封装到task里面,还是需要创建一个线程来跑他的。
而这里task作为一个对象传给线程,要用move,从左值转换到右值。
promise
在一个线程中产生一个值,并在另一个线程中获取这个值。通常与future和async一起使用
#include <iostream>
#include <thread>
#include <memory>
#include <mutex>
#include <windows.h>
#include <string>
#include <condition_variable>
#include <queue>
#include <atomic>
#include <future>
using namespace std;void func(std::promise<int> f){f.set_value(1000);
}int main()
{ std::promise<int> f;auto future_result=f.get_future();std::thread t1(func,std::move(f));t1.join();cout<<future_result.get()<<endl;return 0;
}
或者用引用传入
get()
也会阻塞线程,直到promise的执行完毕
原子操作
std::atmoic
除了用互斥量来解决死锁问题,原子操作也能保证线程安全。
直接把shared_data变成一个原子变量,这个与加锁效果是一样的
原子操作的运行时间
而加锁操作的运行时间
原子操作比解锁,效率更高。
load()
其实就是输出这个值
store()
对原子变量进行赋值
相关文章:

C++11:多线程编程
目录 线程库基本用法创建线程给线程传递参数线程分离 常见数据未定义错误传递指针或引用指向局部变量的问题传递指针或引用指向已释放的内存的问题类成员函数作为入口函数,类对象被提前释放智能指针来解决该问题入口函数为类的私有成员函数 互斥量死锁 lock_guard与…...

【H2O2|全栈】JS进阶知识(八)ES6(4)
目录 前言 开篇语 准备工作 浅拷贝和深拷贝 浅拷贝 概念 常见方法 弊端 案例 深拷贝 概念 常见方法 弊端 逐层拷贝 原型 构造函数 概念 形式 成员 弊端 显式原型和隐式原型 概念 形式 constructor 概念 形式 原型链 概念 形式 结束语 前言 开篇语…...

OmniDiskSweeper :一款专为 macOS 设计的磁盘使用分析工具
OmniDiskSweeper 是一款专为 macOS 设计的磁盘使用分析工具,由 The Omni Group 开发。它的主要目的是帮助用户可视化磁盘上的文件和文件夹,并找出占用大量空间的文件,从而帮助用户释放磁盘空间。 OmniDiskSweeper 的特点包括: 简…...

【什么是Redis?】
Redis:高性能内存数据库的深度探索 在当今这个数据驱动的世界里,数据库的选择直接关系到应用程序的性能、可扩展性和可靠性。在众多数据库解决方案中,Redis以其卓越的性能、丰富的数据结构和灵活的使用场景脱颖而出,成为众多开发…...

React第十六章(useLayoutEffect)
useLayoutEffect useLayoutEffect 是 React 中的一个 Hook,用于在浏览器重新绘制屏幕之前触发。与 useEffect 类似。 用法 useLayoutEffect(() > {// 副作用代码return () > {// 清理代码}}, [dependencies]);参数 setup:Effect处理函数,可以返回…...

shell 基础知识2 ---条件测试
目录 一、条件测试的基本语法 二、文件测试表达式 三、字符串测试表达式 四、整数测试表达式 五、逻辑操作符 六、实验 为了能够正确处理 Shell 程序运行过程中遇到的各种情况, Linux Shell 提供了一组测试运算符。 通过这些运算符,Shell 程序能够…...

【线程】Java线程操作
【线程】Java线程操作 一、启动线程1.1 run()和start()的区别 二、终止线程三、等待线程四、线程的状态 一、启动线程 Java中通过start()方法来启动一个线程,其次我们要着重理解start()和run()的区别。 1.1 run()和start()的区别 我们通过一份代码来进行观察&…...

Linux内核
Linux内核是Linux操作系统的核心部分,它管理着硬件资源并提供基本的服务给用户程序。以下是Linux内核的几个关键方面: 1. 架构: 单内核设计:Linux采用的是单内核设计,这意味着所有操作系统服务都在一个地址空间内运行…...

Sentinel服务保护
Sentinel是阿里巴巴开源的一款服务保护框架,目前已经加入SpringCloudAlibaba中。官方网站: home | Sentinel Sentinel 的使用可以分为两个部分: 核心库(Jar包):不依赖任何框架/库,能够运行于 Java 8 及以…...

python代码制作数据集的测试和数据质量检测思路
前言 本文指的数据集为通用数据集,并不单是给机器学习领域使用。包含科研和工业领域需要自己制作数据集的。 首先,在制作大型数据集时,代码错误和数据问题可能会非常复杂。 前期逻辑总是简单的,库库一顿写,等排查的时…...

笔记记录 k8s-install
master节点安装: yum upgrade -y 更新系统 yum update -y 升级内核 ifconfig ens33 关闭swap swapoff -a (临时) vim /etc/fstab (永久) #/dev/mapper/cl-swap swap swap defaults 0 0 vim /etc/sysctl.conf vm.swappin…...

丹摩征文活动|基于丹摩算力的可图(Kolors)的部署与使用
Kolors是一个以生成图像为目标的人工智能系统,可能采用了类似于OpenAI的DALLE、MidJourney等文本生成图像的技术。通过自然语言处理(NLP)和计算机视觉(CV)相结合,Kolors能够根据用户提供的文本描述生成符合…...

【Vue】 npm install amap-js-api-loader指南
前言 项目中的地图模块突然打不开了 正文 版本太低了,而且Vue项目就应该正经走项目流程啊喂! npm i amap/amap-jsapi-loader --save 官方说这样执行完,就这结束啦!它结束了,我还没有,不然不可能记录这篇文…...

MacOS下的Opencv3.4.16的编译
前言 MacOS下编译opencv还是有点麻烦的。 1、Opencv3.4.16的下载 注意,我们使用的是Mac,所以ios pack并不能使用。 如何嫌官网上下载比较慢的话,可以考虑在csdn网站上下载,应该也是可以找到的。 2、cmake的下载 官网的链接&…...

Android中的依赖注入(DI)框架Hilt
Hilt 是 Android 提供的一种依赖注入(DI)框架,它基于 Dagger,目的是简化依赖注入的使用,提供更易用的接口和与 Android 生命周期组件的紧密集成。下面是 Hilt 的详细介绍。 为什么选择 Hilt? 依赖注入的优势…...

5.STM32之通信接口《精讲》之USART通信---实验串口接收程序
根据上节,我们一已经完成了串口发送程序的代码,并且深入的解析探索了串口的原理,接下来,Whappy小编将带领大家进入串口接收程序的探索与实验,并将结合上一节串口发送一起来完成串口的发送和接收实验。 上来两张图 上图…...

【Redis_Day6】Hash类型
【Redis_Day6】Hash类型 Hash类型操作hash的命令hset:设置hash中指定的字段(field)的值(value)hsetnx:想hash中添加字段并设置值hget:获取hash中指定字段的值hexists:判断hash中是否…...

[开源] SafeLine 好用的Web 应用防火墙(WAF)
SafeLine,中文名 “雷池”,是一款简单好用, 效果突出的 Web 应用防火墙(WAF),可以保护 Web 服务不受黑客攻击 一、简介 雷池通过过滤和监控 Web 应用与互联网之间的 HTTP 流量来保护 Web 服务。可以保护 Web 服务免受 SQL 注入、XSS、 代码注…...

40分钟学 Go 语言高并发:Select多路复用
Select多路复用 学习目标 知识点掌握程度应用场景select实现原理深入理解底层机制channel通信和多路选择超时处理掌握超时控制方法避免阻塞和资源浪费优先级控制理解优先级实现处理多个channel的顺序性能考虑了解性能优化点高并发场景优化 1. Select实现原理 让我们通过一个…...

candence: 如何快速设置SUBCLASS 的颜色
如何快速设置SUBCLASS 的颜色 一、一般操作 正常情况下修改SUBCLASS,需要如下步骤进行设置: 二、快速操作 右键,选择一个颜色即可...

FinalShell进行前端项目部署及nginx配置
首先需要准备服务器(阿里云、腾讯云都可)与域名; 示例为阿里云服务器; 1.进行FinalShell下载 下载官网 https://www.hostbuf.com/ 2.下载完毕后 配置FinalShell ssh 名称自定义即可! 2-1 提示连接成功 3.首先检查nginx是否下载 …...

神经网络(系统性学习一):入门篇——简介、发展历程、应用领域、基本概念、超参数调优、网络类型分类
相关文章: 神经网络中常用的激活函数 神经网络简介 神经网络(Neural Networks)是受生物神经系统启发而设计的数学模型,用于模拟人类大脑处理信息的方式。它由大量的节点(或称为“神经元”)组成࿰…...

用nextjs开发时遇到的问题
这几天已经基本把node后端的接口全部写完了,在前端开发时考虑时博客视频类型,考虑了ssr,于是选用了nextJs,用的是nextUi,tailwincss,目前碰到两个比较难受的事情。 1.nextUI个别组件无法在服务器段渲染 目前简单的解决方法&…...

微前端基础知识入门篇(二)
概述 在上一篇介绍了一些微前端的基础知识,详见微前端基础知识入门篇(一)。本文主要介绍qiankun微前端框架的实战入门内容。 qiankun微前端实践 通过Vite脚手架分别创建三个程序,主应用A为:vite+vue3+ts,两个微应用分别为B:vite+vue3+ts;C:vite+React+ts。因为qiankun的…...

自然语言处理:第六十五章 MinerU 开源PDF文档解析方案
本人项目地址大全:Victor94-king/NLP__ManVictor: CSDN of ManVictor 原文地址:MinerU:精准解析PDF文档的开源解决方案 论文链接:MinerU: An Open-Source Solution for Precise Document Content Extraction git地址࿱…...

Arcpy 多线程批量重采样脚本
Arcpy 多线程批量重采样脚本 import arcpy import os import multiprocessingdef resample_tifs(input_folder, output_folder, cell_size0.05, resampling_type"BILINEAR"):"""将指定文件夹下的所有 TIFF 文件重采样到指定分辨率,并输出…...

python 画图例子
目录 多组折线图点坐标的折线图 多组折线图 数据: 第1行为x轴标签第2/3/…行等为数据,其中第一列为标签,后面为y值 图片: 代码: import matplotlib.pyplot as plt# 原始数据字符串 # 第1行为x轴标签 # 第2/3/...行等为数据,其中第一列为标签,后面…...

Win11 22H2/23H2系统11月可选更新KB5046732发布!
系统之家11月22日报道,微软针对Win11 22H2/23H2版本推送了2024年11月最新可选更新补丁KB5046732,更新后,系统版本号升至22621.4541和22631.4541。本次更新后系统托盘能够显示缩短的日期和时间,文件资源管理器窗口很小时搜索框被切…...

【STM32】MPU6050初始化常用寄存器说明及示例代码
一、MPU6050常用配置寄存器 1、电源管理寄存器1( PWR_MGMT_1 ) 此寄存器允许用户配置电源模式和时钟源。 DEVICE_RESET :用于控制复位的比特位。设置为1时复位 MPU6050,内部寄存器恢复为默认值,复位结束…...

深度学习中的mAP
在深度学习中,mAP是指平均精度均值(mean Average Precision),它是深度学习中评价模型好坏的一种指标(metric),特别是在目标检测中。 精确率和召回率的概念: (1).精确率(Precision):预测阳性结果中实际正确的比例(TP / …...