Linux 线程(上)
前言:大家早上中午晚上好!!今天来学习一下linux系统下所谓的线程吧!!!
一、重新理解进程,什么是进程?
1.1 图解
其中黑色虚线部分一整块就是进程,注意:一整块指的是:①:从一个程序运行起来后成为进程,OS堆这个进程进行描述PCB结构、②这个PCB中的进程地址空间所映射的物理内存资源、③页表,等等。。。总而言之:所有保证这个进程正常运行的所有资源!!
也就是说:进程是系统资源分配的基本单位,每一个进程的资源由系统分配,分配出来后的整一块资源都属于进程,进程相当于大家庭;
1.2、Linux系统下的线程
图解:
图中通过第一个创建的PCB描述出来的PCB2、PCB3、PCB4、PCB5暂时可以把它理解为线程!!(注意:只是暂时把它认为是线程);
这些通过主线程描述出来的PCB2、3、4、5.....等他们共同瓜分进程地址空间,而这个地址空间就是资源的窗口(通过页表跟物理内存建立一一映射关系),所以相当于同一进程下所有线程在同一块资源下进行瓜分,然后这些线程就可以分别执行自己的任务!!!(所以线程相当于家庭中的每一个成员:爸爸、妈妈、爷爷、奶奶、哥哥、姐姐、等!!)
1.3线程的调度
创建并完成资源分配后,cpu就可以对一个个PCB进行调度了,让他们分别执行代码中的某一部分内容,各自完成自己的任务!!所以:线程是cpu调度的基本单位
二、pthread库
2.1、pthread库是什么先不管,先用,先写一段代码
写一段代码实现创建一个线程,并让它执行自己的任务:
写之前先介绍一个创建线程的接口:
首先第一个参数为:输出型参数,需要自己定义pthread_t 类型变量,把这个变量地址传入,创建完成后获取到pthread_t;
第二个参数:线程属性,不需要修改设置为nullptr即可;
第三个参数:线程的入口函数,这个线程一被调用就会从入口函数开始执行,这个函数自己定义,这个函数的返回值是void*类型,参数为void*类型;
第四个参数:给入口函数传送的形参,如果不许要传设置为nullptr;
创建完线程,线程跑完后要对线程进程回收;
介绍一个等待线程的接口:
第一个参数:为线程的tid,传入哪个tid就等待哪个线程;
第二个参数为:获取这个线程的退出信息,如果不需要设置为nullptr;
返回值int:如果等待成功返回0,如果失败返回错误码;
有了这两个接口我们就来写一段代码吧:
#include <iostream>
using namespace std;
#include <pthread.h>
#include <unistd.h>
void* print(void* args)
{int cnt=10;while(cnt--){cout<<"i am a thread !!!!"<<endl;sleep(1);}return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,print,nullptr);//线程创建int cnt2=10;while(cnt2--){cout<<"i am a main thread!!!!"<<endl;sleep(1);}int n=pthread_join(tid,nullptr);//线程等待if(n==0)cout<<"wait success!!!"<<endl;return 0;
}
当我们编译的时候发现报错:
原因是因为pthread.h是动态库,我们编译的时候需要加上 -lpthread 才能链接成功:
makefile:
mythread:mythread.ccg++ -o $@ $^ -std=c++11 -lpthread //编译时加上-lpthread
.PHONY:clean
clean:rm -f mythread
编译成功并生成mythread可执行程序:
运行:
我们看到主线程和分线程分别打印了10次,并成功等待了线程;
2.2 批量创建线程
上面我们创建的是一个线程,如果我们想批量创建线程呢?
那很简单,用一个for循环创建线程同时把tid保存起来,再用一个for循环等待tid:
同时我们每个线程获取一下pid_t(进程pid),同时每个线程获取一下pthread_t(tid),同时用轻量级命令 :ps- aL 查看所有轻量级进程:
#include <iostream>
using namespace std;
#include <pthread.h>
#include <unistd.h>
#include <vector>
#define THREAD_NUM 5
void* print(void* args)
{cout<<"i am a thread !!!! tid is :"<<pthread_self()<<" pid is:"<<getpid()<<endl;sleep(1);return nullptr;
}
int main()
{vector<pthread_t> tids;//批量创建线程并保存tidfor(int i=0;i<THREAD_NUM;i++){pthread_t tid;pthread_create(&tid,nullptr,print,nullptr);tids.push_back(tid);}for(int i=0;i<THREAD_NUM;i++){int n=pthread_join(tids[i],nullptr);//线程批量等待if(n==0)cout<<"wait success!!! tid is : "<<tids[i]<<endl;}return 0;
}
编译后运行:
同时命令行输入ps - aL:
我们发现所有线程它的pid 都是相同的,tid是一串很长的数字且都是不相同的,用ps -aL命令查看到LWP中只一个数字15304是跟pid一样其他都不相同!!
pthread_t tid 究竟是什么?LWP是什么?他们跟PID之间的关系是什么?还有pthread库又是什么?
2.3重新理解线程
①:在linux系统下一般把线程称为轻量级进程,因为在Linux内核中没有用新的数据结构来描述线程,而是通过原有的进程PCB来描述线程的!!
②: 因此linux系统是通过LWP来对这些所谓的 “线程” 进行调度的,LWP就是:light weight process (轻量级进程的意思),所以在linux下所谓的线程:就是一个个通过(第一个创建出来的进程的PCB)描述出来的轻量级进程!
③: 那么linux系统不创建新的数据结构来描述线程,等于linux不想管理这些线程,那么谁来管理?pthread库!!来了!pthread库是第三方库,当我们安装linux操作系统的时候必须把pthread库安装好,这个pthread库里有别人编写好的一系列对线程操作的接口,且这个库需要管理每一个用户创建出来的线程!!!怎么管理?->先描述再组织!->pthread库必须有一个描述线程的数据结构(TCB)->pthread库通过对一个个TCB的管理从而管理一个个线程!!
④线程由pthread库管理,pthread库不属于OS内核,所以线程不属于OS内核!!在linux下所谓的线程是用户级线程!!
当pthread库调用一系列的pthread_create、pthread_join、等接口时其底层调用的其实是clone这个系统调用接口:
图解:
所以我们可以回答上面的第一个问题了:pthread_t tid 究竟是什么:
pthread_t tid 是用户级线程的tid!!所谓用户级就是管理线程的pthread库属于用户级!!每一个TCB有其对应的tid,用户通过tid便可以指定对某个线程进行操作!!
然后我们还能回答第二个问题了:LWP是什么:
图解:
我们知道每个PCB都有它的PID,linux下的“线程”是通过进程的PCB描述出来的;
当它被描述出来之后就是一个所谓的“线程”了,也就是称为了cup调度的基本单位!
而PID代表的是进程,所谓进程代表的是被分配到的整块资源,所有“线程”共享的这一个块资源;
因此所有的“线程”的PID只有一个!!这些新创建出来的“线程”所以用LWP来标志!!
如果LWP跟PID一样说明这是第一个被创建出来的“线程”,即主线程!!!
最后cup就能通过LWP调度到每个它想调度的“线程”!!
同时我们可以回答第三个问题:pthread库是什么:
因为linux内核不管理线程,所以linux中把线程称之为:轻量级进程(它管理的是进程);
因为线程需要被管理,所以linux必须安装有pthread库;
pthread库就是用来管理用户创建除了的一切线程;
既然要管理所以pthread库必须对线程进行描述,必须要有TCB结构,通过一个个TCB结构的管理实现对所有线程的管理;
因此Linux下的所谓线程其实是用户级线程,那么我们可以这么认为:Linux下的线程=LWP(linux内核中的PCB轻量级进程标志)+pthread_t TID(用户中的TCB线程的标志);
三、线程的控制
3.1 线程的分离
如果主线程不想等待分支线程,我们可以让线程自己分离,分离后由OS进行;
线程分离接口:
#include<pthread.h>
int pthread_detach(pthread_t thread);
//1. 这是用来分离线程的pthread库接口
//2. thread:你想分离的线程的tid
//3. 返回值int,如果分离成功返回0,如果分离错误返回错误码
获取当前线程tid接口:
#include <pthread.h>
pthread_t pthread_self(void);
//1. pthread_t 返回值如果获取成功返回当前线程的tid
代码:
我们分离的同时等待一下线程看看能否等待成功:
线程分离的两种方法:线程自己分离:
#include <iostream>
using namespace std;
#include <pthread.h>
#include <unistd.h>
#include <vector>
#include <cstring>
#define THREAD_NUM 5
void* print(void*args)
{pthread_detach(pthread_self());cout<<"i am a thread!!"<<endl;return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,print,nullptr);sleep(1);//等待1s让线程分离完成int code=pthread_join(tid,nullptr);if(code==0){cout<<"wait success !!"<<endl;}elsecout<<"wait false!! error num is:" <<code<<"error message :"<<strerror(code)<<endl;return 0;
}
编译运行:
线程分离成功,主线程等待失败,返回22错误码,意思是无效的参数,也就是没有等待到对应的tid;
线程分离方法二:主线程让他分离:
编译运行:
结果一样,说明成功分离分支线程;
3.2 线程的退出
线程退出的几种方式:
①线程运行完走到return 正常退出;
②终止线程的接口:
#include<pthread.h>
void pthread_exit(void* retval);
//1. retval 可以传入退出信息,由外部线程等待函数获取
我们退出的同时可以传入参数retval让主线程获取退出信息:
主线程等待获取线程退出信息需要传入一一个二级参数,因为join的第二个参数是一个输出型参数:
void* print(void*args)
{cout<<"i am a thread!!"<<endl;pthread_exit((void*)100);return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,print,nullptr);sleep(1);void*retval;pthread_join(tid,&retval);(long long int)retval;printf("%d\n",retval);return 0;
}
编译运行:
100退出码被带了出来;
③还有一个线程会终止的场景:当同一线程组内的任一线程出现异常,接收到终止信号,那么整个进程会崩溃,所有线程都会退出;
3.3 线程的取消
主线程可以取消一个线程,前提是这个线程已经被启动:
取消线程的接口:
#include<pthread.h>
int pthread_cancel( pthread_t thread);
//1. 取消一个线程,前提这个线程被启动
//2. thread : 需要取消的线程的tid
//3. 如果成功返回0,失败返回一个错误码
void* print(void*args)
{while(true){cout<<"i am a thread!!"<<endl;sleep(1);}return nullptr;
}
int main()
{pthread_t tid;pthread_create(&tid,nullptr,print,nullptr);int code= pthread_cancel(tid);if(code==0){cout<<"取消成功"<<endl;}elsecout<<"取消失败"<<endl;//sleep(1);//线程已被启动pthread_join(tid,nullptr);return 0;
}
运行:
四、总结线程的特点
4.1 、线程是系统调度的基本单位,进程是资源分配的基本单位;
4.2、线程的粒度小于进程,占用资源更少,因此通常多线程比多进程更高效;
4.3、线程没有独立的地址空间,线程是划分进程的地址空间,本质上使用的是同一地址空间!线程不拥有系统资源,线程共享进程的资源!
4.4、大量的计算使用多线程和多进程都可以实现并行/并发处理,区别在于线程的资源消耗小于进程,线程的稳定性不如进程,因此需要具体更细致的需求场景;
4.5、线程除了独立的栈空间和一组寄存器(保存线程的上下文)其他线程看不到之外其他所有资源都是所有线程共享的;
4.6、线程的通信速度更快,切换更快,因为他们在同地址空间内,且还共享了很多其他进程资源,比如页表指针,这些是不需要切换的!
今天的分享就到这里!如果对你有所帮助记得点赞收藏+关注哦!!谢谢!!!
咱下期见!!!
相关文章:
Linux 线程(上)
前言:大家早上中午晚上好!!今天来学习一下linux系统下所谓的线程吧!!! 一、重新理解进程,什么是进程? 1.1 图解 其中黑色虚线部分一整块就是进程,注意:一整…...
# 终端执行 java -jar example.jar 时(example.jar为项目jar包)报错:“没有主清单属性” 的解决方法
终端执行 java -jar example.jar 时(example.jar为项目jar包)报错:“没有主清单属性” 的解决方法 在Java中,一个JAR文件必须包含一个主清单属性(Main-Class属性)才能在命令行中直接运行。如果你在尝试运行…...
4:OpenCV—保存图像
将图像和视频保存到文件 在许多现实世界的计算机视觉应用中,需要保留图像和视频以供将来参考。最常见的持久化方法是将图像或视频保存到文件中。因此,本教程准备解释如何使用 OpenCV C将图像和视频保存到文件中。 将图像保存到文件 可以学习如何保存从…...
[C++面试] const相关面试题
1、非 const 的引用必须指向一个已存在的变量 int main() {int &a 20; // 错误const int &b 30; } 字面量 20 是临时值(右值),没有明确的内存地址。非常量引用(左值引用)不能直接绑定到右值(如…...
#Redis黑马点评#(六)Redis当中的消息队列
目录 Redis当中的消息队列 一 基于List 二 基于PubSub 三 基于Stream 单消费模式 消费者组 Redis当中的消息队列 消息队列,字面意思就是存放消息的队列。最简单的消息队列模型包括3个角色: 消息队列:存储和管理消息,也称为…...
Git基础原理和使用
Git 初识 一、版本管理痛点 在日常工作和学习中,我们经常遇到以下问题: - 通过不断复制文件来保存历史版本(如报告-v1、报告-最终版等) - 版本数量增多后无法清晰记住每个版本的修改内容 - 项目代码管理存在同样问题 二、版本控…...
Java程序员学AI(一)
一、前言 最近刷技术圈,满眼都是 GPT、DeepSeek、QWen 这些 AI 名词。看着同行们在群里聊 AI 写代码、做数据分析,我这个摸了 Java 老程序员突然慌了 —— 再不出手,怕是真要被时代落下了! 作为一个 Java 死忠粉,学 …...
《Python星球日记》 第91天:端到端 LLM 应用(综合项目:医疗文档助手)
名人说:路漫漫其修远兮,吾将上下而求索。—— 屈原《离骚》 创作者:Code_流苏(CSDN)(一个喜欢古诗词和编程的Coder😊) 目录 一、项目概述与需求分析1. 项目背景2. 项目目标3. 技术栈概览二、数据准备与处理1. 文档收集策略2. 文本预处理流程3. 向量化与知识库构建三、模…...
目前主流的AI测试工具推荐
以下是目前备受关注的AI测试工具及平台,涵盖功能测试、视觉测试、性能测试及国产化解决方案等多个领域,结合其核心特性与适用场景进行综合推荐: 一、主流AI测试工具推荐 Testim 核心功能:基于AI的动态元素定位技术,…...
vscode优化使用体验篇(快捷键)
本文章持续更新中 最新更新时间为2025-5-18 1、方法查看方法 1.1当前标签跳到新标签页查看方法实现 按住ctrl 鼠标左键点击方法。 1.2使用分屏查看方法实现(左右分屏) 按住ctrl alt 鼠标左键点击方法。...
uniprot中PTM数据的下载
首先是PTM的介绍: 参考:https://en.wikipedia.org/wiki/Post-translational_modification 蛋白质的翻译后修饰(PTM)通过改变氨基酸残基的化学结构,显著影响其带电性质,从而调控蛋白质的功能、定位和相互作…...
【QGIS二次开发】地图编辑-04
系列目录: 【QGIS二次开发】地图显示与交互-01_qgis二次开发加载地图案例-CSDN博客 【QGIS二次开发】地图显示与交互-02_setlayerlabeling-CSDN博客 【QGIS二次开发】地图符号与色表-03-CSDN博客 4 地图编辑 4.1 添加点要素 功能演示: 运行程序后…...
Qt 信号和槽-核心知识点小结(11)
目录 小结表格索引 disconnect函数 lambda表达式 啥是耦合,啥是内聚 简介:这是Qt信号和槽的最后一篇文章,最主要的是总结该信号和槽的核心知识点。以及该核心知识点的文章索引(表格太长了,手机可能看不完整&#…...
React响应事件中onClick={handleClick} 的结尾有没有小括号的区别
你可以通过在组件中声明 事件处理 函数来响应事件: function MyButton() {function handleClick() {alert(You clicked me!);}return (<button onClick{handleClick}>点我</button>);} 注意,onClick{handleClick} 的结尾没有小括号&#x…...
React-Query使用react-testing-library进行测试
1.测试react-query首先我们必须得拥有queryClient,所以我们初始化queryClient,因为默认是重试三次,这意味着如果想测试错误的查询,测试可能会超时。所以可以在初始化时关闭 const createWrapper () > {const queryClient new…...
软件设计师CISC与RISC考点分析——求三连
一、考点分值占比与趋势分析(CISC与RISC) 综合知识分值统计表 年份考题数量分值分值占比考察重点2018111.33%指令特征对比2019111.33%控制器实现方式2020222.67%寄存器数量/流水线技术2021111.33%寻址方式对比2022222.67%指令复杂度/译码方式2023111.3…...
GO语言(一期)常用关键字总结
GO语言(主题一)常用关键字总结 我们这里列出一些go语言关键字,方便各位友友们检查一下自己的学习效果,也方便友友们学习查询。 break default func interface select case defer go map …...
Ubuntu搭建NFS服务器的方法
0 工具 Ubuntu 18.041 Ubuntu搭建NFS服务器的方法 在Ubuntu下搭建NFS(网络文件系统)服务器可以让我们像访问本地文件一样访问Ubuntu上的文件,例如可以把开发板的根文件系统放到NFS服务器目录下方便调试。 1.1 安装nfs-kernel-server&#…...
京东商品详情API接口开发指南(含Java/Python实现)
接口概述 京东开放平台提供了商品详情查询接口,开发者可以通过SKUID获取商品的详细信息,包括标题、价格、图片、促销信息等。该接口需要申请API权限和认证密钥。 点击获取key和secret 接口特点 支持批量查询(最多20个SKU)返回J…...
二叉树构造:从前序、中序与后序遍历序列入手
目录 引言 从前序与中序遍历序列构造二叉树(题目 105) 解题思路 举例说明 从中序与后序遍历序列构造二叉树(题目 106) 解题思路 举例说明 总结 引言 二叉树的遍历与构造是算法领域中的经典问题。LeetCode 上的“从前序与中…...
GEE谷歌地球引擎批量下载逐日ERA5气象数据的方法
本文介绍在谷歌地球引擎(Google Earth Engine,GEE)中,批量下载逐日的ERA5土壤湿度数据(或者是其他气象数据、遥感影像数据等)的方法。 首先,明确一下本文的需求。我们希望在GEE中,下…...
C#接口(Interface)全方位讲解:定义、特性、应用与实践
引言 在面向对象编程(OOP)中,接口(Interface)是一种重要的结构,它定义了某一类对象或类应遵循的行为规范。接口强调“做什么(What)”,而非“怎么做(How&…...
索引与数据结构、并行算法
3. 索引与数据结构 索引类比目录:类似于书籍目录,帮助我们快速定位信息。索引的核心目的:提升数据查找效率,优化增删改查性能。实际应用广泛:MySQL、Redis、搜索引擎、分布式系统、中间件等。 3.1. 索引设计中的需求…...
GC全场景分析
GC全场景分析 文章目录 GC全场景分析标记-清除法**标记 - 清除法核心流程与 STW 机制****标记 - 清除法四步流程****1. STW 启动(暂停用户线程)****2. 标记可达对象(从根集合出发)****3. 清除未标记对象(回收堆内存&am…...
OSI七层模型和TCP/IP的五层(四层模型)
分层 1.什么是分层 我理解是对同一相同或者相似的事务或者操作功能进行分类,比如我们去餐厅吃饭,就可以分为好多层,客户层,服务员层,前台层,后厨层,每一层都专注自己的事情,客户层…...
MouseDown,MouseUp,LostMouseCapture的先后顺序
本文目标是实现如下功能: 按下一个按钮后置位某变量;鼠标松开后复位某个变量? 看似简单,但是一般来说会存在如下两种现象: 鼠标移出按钮:默认会丢失鼠标事件跟踪,即MouseLeftButtonUp事件并不会被触发。 焦点切换:Tab 键切换焦点会干扰按钮的事件捕获 本文通过几个…...
第8章 常用实用类
8.1 String类 在java.lang包(默认引入)中,可直接使用。 定义为final类,不能扩展String类,不可以继承,不可以有子类。 8.1.1 构造String对象 常量对象: 英文双引号括起来 String常量放入常…...
视差场(disparity field)
视差场(disparity field)是立体视觉中的一个重要概念,用于描述两幅立体图像之间像素的对应关系。以下是对视差场的详细解释: 1. 视差(Disparity)的定义 视差是指同一场景点在两幅立体图像中的像素位置差异…...
AI:OpenAI论坛分享—《AI重塑未来:技术、经济与战略》
AI:OpenAI论坛分享—《AI重塑未来:技术、经济与战略》 导读:2025年4月24日,OpenAI论坛全面探讨了 AI 的发展趋势、技术范式、地缘政治影响以及对经济和社会的广泛影响。强调了 AI 的通用性、可扩展性和高级推理能力,以…...
【已经解决诸多问题】Mamba安装
mamba被称为新一代的计算架构,因此在CV和时序领域存在诸多的方案开始采用这一新架构,但是这个架构的安装过程中存在诸多问题!!!!为了更好帮助大家理解我们给出一个统一的安装流程!!&…...
计算机的基本组成与性能
1. 冯诺依曼体系结构:计算机组成的金字塔 1.1. 计算机的基本硬件组成 1.CPU - 中央处理器(Central Processing Unit)。 2.内存(Memory)。 3.主板(Motherboard)。主板的芯片组(Ch…...
“绿色邮政,智能九识”——呼和浩特邮政无人快递车发车,驶向智慧物流新时代!
5月12日,“绿色邮政,智能九识”呼和浩特邮政无人驾驶快递车发车。 此次投运的邮政无人驾驶快递车实力惊人:单车运量超1000件,时速达40公里,通过智能路径规划实现24小时作业,与传统运输相比,运转…...
AGI大模型(24):通过LangChain的接口来调用OpenAI对话
1 创建对话 使用langchain库中的ChatOpenAI类来创建一个对话模型。 from dotenv import load_dotenvload_dotenv()import os from langchain_openai import ChatOpenAIllm = ChatOpenAI(api_key=os.getenv("DEEPSEEK_API_KEY"),base_url="https://api.deepsee…...
大模型中的Token机制深度解析
目录 大模型中的Token机制深度解析 一、Token的本质与核心作用 二、主流分词算法对比 三、GPT-3分词机制详解 四、分词策略对模型性能的影响 五、工程实践建议 六、未来演进方向 一、Token的本质与核心作用 Token是大模型处理文本的最小语义单元,类似于人类语…...
【MySQL】库与表的操作
一、库的操作 1. 查看数据库 语法:show databases;这里的database是要加s的 查看当前自己所处的数据库:select database(); 例如下图,我当前所处的数据库就是在class1数据库 2. 创建数据库 语法:create database [if not e…...
创建指定版本的vite项目
1、获取vite的版本号 npm view create-vite versions 注:4.4.1版本即对应着node16版本的项目 2、创建制定版本的vite项目 npm init vite<version>...
java中的Servlet3.x详解
Servlet 3.x 是 Java Web 开发的重要里程碑,包含 Servlet 3.0(2009年发布)和 Servlet 3.1(2013年发布)两个主要版本。它通过多项革新优化了开发效率、性能及扩展性,成为现代 Java Web 应用的核心技术基础。…...
单目测距和双目测距 bev 3D车道线
单目视觉测距原理 单目视觉测距有两种方式。 第一种,是通过深度神经网络来预测深度,这需要大量的训练数据。训练后的单目视觉摄像头可以认识道路上最典型的参与者——人、汽车、卡车、摩托车,或是其他障碍物(雪糕桶之类…...
weibo_comment_pc_tool | 我于2025.5月用python开发的评论采集软件,根据帖子链接爬取评论的界面工具
本工具仅限学术交流使用,严格遵循相关法律法规,符合平台内容的合法及合规性,禁止用于任何商业用途! 一、背景分析 1.1 开发背景 微博(以下简称wb)是国内极具影响力的社交媒体平台,具有内容形式…...
ubuntu防火墙命令和放行ssh端口
一、关闭UFW防火墙(Ubuntu默认工具) 1. 临时关闭防火墙 sudo ufw disable sudo ufw status # 显示 Status: inactive 表示已关闭 2. 永久禁用防火墙(禁用系统服务) sudo systemctl stop ufw # 立即停止服务 sudo sy…...
PWM讲解+STM32任意频率、占空比、脉宽生成函数介绍
1.PWM讲解 脉冲宽度调制(PWM),是英文“Pulse Width Modulation”的缩写,简称脉宽调制。 脉宽调制 最开始使用PWM时,是做智能车时使用的舵机打角,电机驱动。这都属于比较浅显,普通的应用。下面和大家简单分享一下PWM的…...
C++23 范围迭代器作为非范围算法的输入 (P2408R5)
文章目录 一、引言二、C23及范围迭代器的背景知识2.1 C23概述2.2 范围迭代器的概念 三、P2408R5提案的内容3.1 提案背景3.2 提案内容 四、范围迭代器作为非范围算法输入的优势4.1 代码简洁性4.2 提高开发效率4.3 更好的兼容性 五、具体的代码示例5.1 使用范围迭代器进行并行计算…...
CVE-2018-1273 漏洞深度分析
漏洞概述 CVE-2018-1273 是 Spring Data Commons 中的一个高危远程代码执行(RCE)漏洞,影响版本为 Spring Data Commons 1.13–1.13.10 和 2.0–2.0.5。攻击者通过构造包含恶意 SpEL表达式的 HTTP 请求参数,触发表达式注入&#x…...
C++23:修正常量迭代器、哨兵和范围
文章目录 引言C20范围库回顾C23之前常量迭代器的问题视图可能不传播const代理对象的复杂性泛型代码中的一致性 P2278R4提案及C23的改进std::views::as_const的工作原理代码示例 浅const视图(如std::span)的改进总结 引言 在C的发展历程中,每…...
【漫话机器学习系列】266.雅可比矩阵(Jacobian Matrix)
雅可比矩阵(Jacobian Matrix)详解 | 多变量函数微积分的基石 在深度学习、计算图、优化算法、机器人控制、流形学习等众多领域中,“雅可比矩阵(Jacobian Matrix)”是一个非常核心的数学工具。 这篇文章将结合一张视觉…...
Leetcode 3551. Minimum Swaps to Sort by Digit Sum
Leetcode 3551. Minimum Swaps to Sort by Digit Sum 1. 解题思路2. 代码实现 题目链接:3551. Minimum Swaps to Sort by Digit Sum 1. 解题思路 这一题思路上我实现的非常暴力,就是先求出正确的排列,然后从头考察每一个元素是否处在其目标…...
西门子1200/1500博图(TIA Portal)寻址方式详解
西门子博图(TIA Portal)是西门子公司推出的自动化工程软件平台,广泛应用于工业自动化领域。在编写PLC程序时,寻址方式是一个非常重要的概念,它决定了如何访问和操作PLC中的数据和资源。本文将详细介绍西门子博图中的寻…...
STK手动建链+matlab联调
在右边场景区选择你要建链的卫星,右键在弹出的选项中选择Access 选择你要建链的卫星,这里我选择3轨10星与4轨8星建链,点击compute后再close就行了 建链完成,这里链路的颜色跟起始卫星的颜色一致,要想改变颜色只需改变卫…...
MATLAB中的Switch语句讲解
MATLAB中的Switch语句:一个简单的控制流工具 在MATLAB中,switch语句是一种多分支控制结构,通常用于根据某个表达式的值选择不同的代码块进行执行。它的作用类似于一系列的if-elseif-else语句,但在处理多个条件时,swit…...
【SpringBoot】✈️整合飞书群机器人发送消息
💥💥✈️✈️欢迎阅读本文章❤️❤️💥💥 🏆本篇文章阅读大约耗时3分钟。 ⛳️motto:不积跬步、无以千里 📋📋📋本文目录如下:🎁🎁&am…...