C++ 概览并发
并发
资源管理
资源
- 程序中符合先获取后释放(显式或隐式)规律的东西,比如内存、锁、套接字、线程句柄和文件句柄等。
- RAII: (Resource Acquisition Is Initialization),也称为“资源获取就是初始化”,是C++语言的一种管理资源、避免泄漏的惯用法。
unique_ptr & shared_ptr
- unique_ptr 是一个独立对象或者是数组的句柄,unique_ptr 通过移动操作使得简单高效
- shared_ptr 很多方面和unique_ptr 相似, 唯一区别是shared_ptr 通过拷贝操作而非移动操作。多个shared_ptr 共享该对象的所有权,只有当最后一个 shared_ptr 被销毁时,对象才被销毁。
- shared_ptr 提供的垃圾回收机制需要慎重使用。 shared_ptr 使得对象的生命周期变得不那么容易掌控了,除非在一定程度上一定要使用共享所有权,否则别轻易使用shared_ptr
- shared_ptr 没有指定哪个拥有者有权读写对象
- 当我们使用函数返回集合的时候,不必使用指针,因为如果定义了移动语义, 在返回的时候会默认使用移动操作
并发
任务 和thread
- 线程(thread)是任务在程序中的系统级表示。
- thread 在 中定义
thread 的使用方法
#include <iostream>
#include <thread>
#include <vector>
#include "config.h"// thead 的使用
// 函数的参数这里必须是const, 否则会报thread:120:44: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues
// 在多线程中使用io 操作,需要考虑线程安全,打印出来的字符服务保证输出内容的顺序
void f(const std::vector<double>& v) {std::cout<< "function f" << std::endl;
}
// 通过res 指针返回thread 的执行结果,不美观的方法
// 不推荐使用此方法,因为无法掌控res 什么时候写入了,一般用消息队列,或者使用condition 、promise等方式来实现返回结果
void f2(const std::vector<double>& v, double* res) {}struct F {std::vector<double> & v;F(std::vector<double>& vv):v{vv} {}/* 如果不使用调用运算符重载, 会编译报错: hread:120:44: error: static assertion failed: std::thread arguments must be invocable after conversion to rvalues*/void operator()() { // 调用运算符重载std::cout << "struct F operator" << std::endl;}};class Foo
{
public:void bar(){for (int i = 0; i < 5; ++i){std::cout << "正在执行线程3\n";++n;std::this_thread::sleep_for(std::chrono::milliseconds(10));}}int n = 0;
};int main(int argc, char **argv) {std::vector<double> some_vec {1,2,3,4,5,6};std::vector<double> vec2{10,11,12,13};std::thread t1{f, some_vec}; // 在t1 的线程里面执行函数f, 参数是some_vecstd::thread t2{F{vec2}}; // 在t2 的县城里面执行函数 F 的调用运算符, 参数是vec2double res;std::thread t3(f2, some_vec, &res);Foo f;std::thread t4(&Foo::bar, &f); // t5 在对象 f 上运行 foo::bar()t1.join();t2.join();return 0;
}
- thread 更多用法清参照cppreference
thread 共享数据
- mutex // 访问数据排他处理
- condition_variable 允许一个thread 等待另外一个thread
- 代码示例
class Message {
private:int msgId;
public:Message(int id) : msgId(id){}int getId() { return msgId;}
};std::queue<Message> mMsgQueue;
std::condition_variable mCond;
std::mutex mMutex;void consumer() {while(true) {//std::cout << "wait mutex " << std::endl;std::unique_lock<std::mutex> lck{mMutex};//std::cout << "wait condition " << std::endl;//while(mCond.wait(lck))/*do nothing*/;mCond.wait(lck);//std::cout << "after wait condition " << std::endl;auto m = mMsgQueue.front();mMsgQueue.pop();std::cout << "get msg Id: " << m.getId() << std::endl;// lck.unlock();}
}void producer() {int index = 10;while(index > 0) {Message msg(index);std::unique_lock<std::mutex> lck{mMutex};mMsgQueue.push(msg);std::cout << "push msg Id: " << msg.getId() << std::endl;lck.unlock(); //(1)mCond.notify_all();//std::cout << "after notify all: " << msg.getId() << std::endl;//std::this_thread::sleep_for(std::chrono::milliseconds(20)); //(2)index--;}
}int main(int argc, char **argv) {std::thread t2(consumer);std::thread t1(producer);t1.join();t2.join();
}
-
对于生产者-消费者模式,理想状态下,生产者生产一个,消费者就消费一个,但是实际并非如此
- (1) 如果不主动调用lck.unlock(), lck 需要等到while(){} 进入下一个循环才会释放,所以无论是否加(), cosumer 线程得不到执行的契机(可能和平台有关)
- (2) 对于加了(1) 而没有(2) 的场合while 很快执行到下一个循环,又立即执行到lck, 也会导致在producer 执行过程中,consumer 得不到执行
执行效果大致如下:

-
而如果加了(1) 和(2)后:

-
对于consume 如上图的处理方式,获取一次锁只pop 一次数据,会因为producer notify 和consumer 的wait 不是时间上不是匹配出现而导致数据没有被全部读取出来,可以修改为如下方式:
-
在获取到一次锁后,把消息队列中的消息全部处理掉
void consumer() {while(true) {//std::cout << "wait mutex " << std::endl;std::unique_lock<std::mutex> lck{mMutex};//std::cout << "wait condition " << std::endl;//while(mCond.wait(lck))/*do nothing*/;mCond.wait(lck);//std::cout << "after wait condition " << std::endl;while(!mMsgQueue.empty()) {auto m = mMsgQueue.front();mMsgQueue.pop();std::cout << "get msg Id: " << m.getId() << std::endl;}// lck.unlock();}
}
执行效果大致如下, 这样只是消费者不会立马消费掉生产者生产的数据,但是即使没有(1)(2)也不会导致消息得不到处理:

任务通信
- c++ 中主要提供了以下三种,都定义在 头文件中。
- future and promise 用来从一个独立线程上创建出的任务返回结果
- packaged_task 是帮助启动义务以及链接返回结果的机制
- async 以非常类似调用函数的方式启动一个任务
future and promis
- 允许两个任务间传输直,而无须显示使用锁–“系统”高效地实现了这种传输。
- 当一个任务需要向另一个任务传输这个值时,把它放入promise。
- c++ 实现会出现在对应的future 中。
- 使用future 的get()函数,如果值还未准备好,线程会阻塞直至值准备好。如果get( )无法计算出来,get()会抛一个异常(系统或者从get() 得到数据的任务)
- promise 的作用主要为future的get() 提供放置 操作(set_value()) 和set_exception().
#include <iostream>
#include <thread>
#include <future>
#include <functional>
void work (std::promise<int>& px) {try {px.set_value(11);} catch (...) {px.set_exception(std::current_exception());}
}void result (std::future<int>& res) {try {int result = res.get();std::cout<< " recieve the result: " << result << std::endl;} catch(...) {//std::cout<<"exception"<< std::current_exception() << std::endl;}
}
int main(int argc, char **argv) {std::promise<int> pro;std::future<int> fut = pro.get_future(); //binding the future and the promisestd::thread t1(work, std::ref(pro));std::thread t2(result, std::ref(fut));t1.join();t2.join();return 0;
}
-
可以看到使用步骤如下:
- 声明promise
- 定义future,并且绑定promise 和future, 二者的模板类型必须一致(很好理解,provise 设定的就是传给future 的)
- 使用promise 的set_value()或者set_exception() 传递值
- 使用future 的get() 函数接收值(注意get()是阻塞的)
-
这里使用了std::ref std::ref的使用场景:
- 算法传递可调用对象,而这些对象可能需要引用传递。
- 在多线程之间共享数据,但有希望通过引用传递数据而不是复制。
- std::ref可以使函数接受任何类型的引用而不仅仅是特定类型
packaged_task
- packaged_task 简化了任务连接future & promise.
- (TODO)
相关文章:
C++ 概览并发
并发 资源管理 资源 程序中符合先获取后释放(显式或隐式)规律的东西,比如内存、锁、套接字、线程句柄和文件句柄等。RAII: (Resource Acquisition Is Initialization),也称为“资源获取就是初始化”,是C语言的一种管…...
04-19 周四 GitHub CI 方案设计
04-19 周四 GitHub CI 方案设计 时间版本修改人描述2024年4月19日14:44:23V0.1宋全恒新建文档2024年4月19日17:22:57V1.0宋全恒完成部署拓扑结构的绘制和文档撰写 简介 需求 由于团队最近把代码托管在GitHub上,为解决推理、应用的自动化CI的需要,调研了…...
java日常选择题
题目来自牛客网 1.以下哪个接口的定义是正确的?() A interface B { void print() {} ;} B interface B { static void print();} C.abstract interface B extends A1, A2 //A1、A2为已定义的接口 {abstract void print(){};} D.interface B { void print(); 选D,因…...
安卓串口通訊三
核心代碼如下: package com.example.comandroid;import static android.content.ContentValues.TAG;import android.graphics.Color; import android.os.Bundle; import android.view.View; import android.widget.Button; import android.widget.TextView;import…...
嵌入式交叉编译:Unable to find arm_neon.h
找到文件 搜索了一下,具体目录是: /opt/linux/x86-arm/aarch64-mix210-linux/lib/gcc/aarch64-linux-gnu/7.3.0/include/arm_neon.h 解决办法 INC_ARM/opt/linux/x86-arm/aarch64-mix210-linux/lib/gcc/aarch64-linux-gnu/7.3.0/include./configure …...
Linux下工具tc详细讲解及限制IP和端口实例
首先纠正某一篇博客,TC并不是只管发包不管收包,之前我也很纳闷 知道最后看到了14年前一位大佬的帖子。是ingress! 这里有个非常重要的点就是ingress,如果父类不是他的话是完不成限制源IP的,这个关键词表明你正在添加一个入口队列规…...
Java | Leetcode Java题解之第73题矩阵置零
题目: 题解: class Solution {public void setZeroes(int[][] matrix) {int m matrix.length, n matrix[0].length;boolean flagCol0 false;for (int i 0; i < m; i) {if (matrix[i][0] 0) {flagCol0 true;}for (int j 1; j < n; j) {if (…...
MySQL#MySql表的操作
目录 一、创建表 二、查看表结构 三、修改表 1.修改表的名字 2.新增一个列 3.修改列 4.删除列 5.修改列的名称 四、删除表 一、创建表 语法: CREATE TABLE table_name (field1 datatype,field2 datatype,field3 datatype ) character set 字符集 collate 校…...
git修改版本发布时间
一、场景 发现git版本发布时,服务器时间有误,需要修改。 二、解决 (1)准备 时间戳转换网址:http://shijianchuo.wiicha.com/ (2)SQLite 数据库 连接到安装git的服务器,修改版本表…...
【NodeMCU实时天气时钟温湿度项目 1】连接点亮SPI-TFT屏幕和UI布局设计
前言 从今天开始,我们详解介绍制作实时天气时钟项目的方法步骤,主要分以下几个专题分别进行:(1)连接点亮SPI-TFT屏幕和UI布局设计;(2)NodeMCU的WIFI模式设置及连接;&…...
国内首发 | CSA大中华区启动《AI安全产业图谱(2024)》调研
在人工智能(AI)技术的快速发展浪潮中,AI安全已成为全球关注的焦点。为应对AI安全带来的挑战,确保AI技术的健康发展,全球范围内的研究机构、企业和技术社区都在积极探索解决方案。 在这一背景下,CSA大中华区…...
web页面与原生android通信,调用原生android方法
注册初始化方法JsBridge //JS注册事件监听 function connectWebViewJavascriptBridge(callback) {if (window.WebViewJavascriptBridge) {callback(WebViewJavascriptBridge)} else {document.addEventListener(WebViewJavascriptBridgeReady,function() {callback(WebViewJav…...
Linux的编译器
程序编译的过程 程序的编译过程是将源代码转换为可执行文件的一系列步骤。这个过程涉及多个阶段,主要包括预处理、编译、汇编和链接。下面详细介绍每个阶段: 1. 预处理(Preprocessing) 在实际编译之前,源代码文件首…...
redis--安装
简介 官网:RedisInsight - The Best Redis GUI 各个版本官网下载地址:http://download.redis.io/releases/ Redis和Memcached是非关系型数据库也称为NoSQL数据库,MySQL、Mariadb、SQL Server、PostgreSQL Oracle 数据库属于关系型数据 应用…...
魔法程序员的奥妙指南:Java基本语法
作为一名魔法程序员,精通Java语言是至关重要的。Java作为一种强大的编程语言,在编写优质代码和开发强大应用程序时发挥着重要作用。让我们深入探讨Java基本语法的关键要点,从注释到变量,无所不包! Java基本语法的神秘魔…...
SpringMVC传递参数
1.RequestMapping RequestMapping本身可以处理,get或post,指定了get或post之后,就只能处理对应的请求。 RequestMapping(value{"haihiyo","goodMoring"},methodRequestMethod.POST)2.RestFul风格 RestFul是一种风格 比如:网站的访…...
【Scala---04】函数式编程 『 函数 vs 方法 | 函数至简原则 | 函数式编程』
文章目录 1. 函数 vs 方法1.1 方法(1) 定义方法(2) 运算符即方法 1.2 函数(1) 定义函数(2) 匿名函数 1.3 方法转为函数1.4 可变参数&默认参数 2. 函数至简原则3. 函数式编程3.1 函数式编程思想3.3 函数柯里化&闭包3.5 递归 & 尾递归 4. 补充4.1 访问元祖元素4.2 &g…...
[华为OD] B卷 树状结构查询 200
题目: 通常使用多行的节点、父节点表示一棵树,比如 西安 陕西 陕西 中国 江西 中国 中国 亚洲 泰国 亚洲 输入一个节点之后,请打印出来树中他的所有下层节点 输入描述 第一行输入行数,下面是多行数据,每行以空…...
基于机器学习的学生学习行为自主评价设计与实现
管理员功能: a)学生学习数据管理:可查看学生学习的详情,编辑学生学习的内容,删除和添加学生学习,设置学生学习库存。 b)角色管理:增加删除学生用户,分配学生用户权限,查看学生用户…...
toml与json联系对比
前言 本文简单介绍toml;并且和json转化做对比,以及我对toml设计的理解。 参考: TOML: 简体中文 v1.0.0 json和toml转化工具 在线JSON转toml-toml转JSON - bejson在线工具 正文 数组 说白了,就是一个变量名,有多个…...
51c自动驾驶~合集58
我自己的原文哦~ https://blog.51cto.com/whaosoft/13967107 #CCA-Attention 全局池化局部保留,CCA-Attention为LLM长文本建模带来突破性进展 琶洲实验室、华南理工大学联合推出关键上下文感知注意力机制(CCA-Attention),…...
《用户共鸣指数(E)驱动品牌大模型种草:如何抢占大模型搜索结果情感高地》
在注意力分散、内容高度同质化的时代,情感连接已成为品牌破圈的关键通道。我们在服务大量品牌客户的过程中发现,消费者对内容的“有感”程度,正日益成为影响品牌传播效率与转化率的核心变量。在生成式AI驱动的内容生成与推荐环境中࿰…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
自然语言处理——循环神经网络
自然语言处理——循环神经网络 循环神经网络应用到基于机器学习的自然语言处理任务序列到类别同步的序列到序列模式异步的序列到序列模式 参数学习和长程依赖问题基于门控的循环神经网络门控循环单元(GRU)长短期记忆神经网络(LSTM)…...
【开发技术】.Net使用FFmpeg视频特定帧上绘制内容
目录 一、目的 二、解决方案 2.1 什么是FFmpeg 2.2 FFmpeg主要功能 2.3 使用Xabe.FFmpeg调用FFmpeg功能 2.4 使用 FFmpeg 的 drawbox 滤镜来绘制 ROI 三、总结 一、目的 当前市场上有很多目标检测智能识别的相关算法,当前调用一个医疗行业的AI识别算法后返回…...
稳定币的深度剖析与展望
一、引言 在当今数字化浪潮席卷全球的时代,加密货币作为一种新兴的金融现象,正以前所未有的速度改变着我们对传统货币和金融体系的认知。然而,加密货币市场的高度波动性却成为了其广泛应用和普及的一大障碍。在这样的背景下,稳定…...
使用 SymPy 进行向量和矩阵的高级操作
在科学计算和工程领域,向量和矩阵操作是解决问题的核心技能之一。Python 的 SymPy 库提供了强大的符号计算功能,能够高效地处理向量和矩阵的各种操作。本文将深入探讨如何使用 SymPy 进行向量和矩阵的创建、合并以及维度拓展等操作,并通过具体…...
USB Over IP专用硬件的5个特点
USB over IP技术通过将USB协议数据封装在标准TCP/IP网络数据包中,从根本上改变了USB连接。这允许客户端通过局域网或广域网远程访问和控制物理连接到服务器的USB设备(如专用硬件设备),从而消除了直接物理连接的需要。USB over IP的…...
基于IDIG-GAN的小样本电机轴承故障诊断
目录 🔍 核心问题 一、IDIG-GAN模型原理 1. 整体架构 2. 核心创新点 (1) 梯度归一化(Gradient Normalization) (2) 判别器梯度间隙正则化(Discriminator Gradient Gap Regularization) (3) 自注意力机制(Self-Attention) 3. 完整损失函数 二…...
2025年渗透测试面试题总结-腾讯[实习]科恩实验室-安全工程师(题目+回答)
安全领域各种资源,学习文档,以及工具分享、前沿信息分享、POC、EXP分享。不定期分享各种好玩的项目及好用的工具,欢迎关注。 目录 腾讯[实习]科恩实验室-安全工程师 一、网络与协议 1. TCP三次握手 2. SYN扫描原理 3. HTTPS证书机制 二…...
