鸿蒙内核源码分析(Shell解析篇) | 应用窥视内核的窗口
系列篇从内核视角用一句话概括shell的底层实现为:两个任务,三个阶段。其本质是独立进程,因而划到进程管理模块。每次创建shell进程都会再创建两个任务。
- 客户端任务(ShellEntry): 负责接受来自终端(控制台)敲入的一个个字符,字符按
VT规范组装成一句句的命令。 - 服务端任务(ShellTask): 对命令进行解析并执行,将结果输出到控制台。
而按命令生命周期可分三个阶段. - 编辑: 鸿蒙在这个部分实现了一个简单的编辑器功能,处理控制台输入的每个字符,主要包括了对控制字符 例如
<ESC>,\t,\b,\n,\r,四个方向键0x41~0x44的处理。 - 解析: 对编辑后的字符串进行解析,解析出命令项和参数项,找到对应的命令项执行函数。
- 执行: 命令可通过静态和动态两种方式注册到内核,解析出具体命令后在注册表中找到对应函数回调。将结果输出到控制台。
编辑部分由客户端任务完成,后两个部分由服务端任务完成,命令全局注册由内核完成。
- 本篇主要说 服务端任务 和 解析/执行过程.
- 客户端任务 和 编辑过程 已在 (Shell编辑篇) 中说明,请自行翻看.
总体过程
- 第一步: 将支持的
shell命令注册进全局链表,支持静态和动态两种方式,内容包括命令项,参数信息和回调函数. - 第二步: 由独立任务解析出用户输入的命令行,拆分出命令项和参数内容
- 第三步: 通过命令项在全局链表中遍历找到已注册的回调函数,并执行.
结构体
鸿蒙对命令的注册用了三个结构体,个人感觉前两个可以合成一个,降低代码阅读难度.
STATIC CmdModInfo g_cmdInfo;//shell 命令模块信息,上面挂了所有的命令项(ls,cd ,cp ==)typedef struct {//命令项CmdType cmdType; //命令类型//CMD_TYPE_EX:不支持标准命令参数输入,会把用户填写的命令关键字屏蔽掉,例如:输入ls /ramfs,传入给注册函数的参数只有/ramfs,而ls命令关键字并不会被传入。//CMD_TYPE_STD:支持的标准命令参数输入,所有输入的字符都会通过命令解析后被传入。const CHAR *cmdKey; //命令关键字,例如:ls 函数在Shell中访问的名称。UINT32 paraNum; //调用的执行函数的入参最大个数,暂不支持。CmdCallBackFunc cmdHook;//命令执行函数地址,即命令实际执行函数。
} CmdItem;
typedef struct { //命令节点LOS_DL_LIST list; //双向链表CmdItem *cmd; //命令项
} CmdItemNode;/* global info for shell module */
typedef struct {//shell 模块的全局信息CmdItemNode cmdList; //命令项节点UINT32 listNum;//节点数量UINT32 initMagicFlag;//初始魔法标签 0xABABABABLosMux muxLock; //操作链表互斥锁CmdVerifyTransID transIdHook;//暂不知何意
} CmdModInfo;
解读
CmdItem为注册的内容载体结构体,cmdHook为回调函数,是命令的真正执行体.- 通过双向链表
CmdItemNode.list将所有命令穿起来 CmdModInfo记录命令数量和操作的互斥锁,shell的魔法数字为0xABABABAB
第一步 | Shell 注册
- 静态宏方式注册,链接时处理
静态注册命令方式一般用在系统常用命令注册,鸿蒙已支持以下命令.
arp cat cd chgrp chmod chown cp cpup date dhclient dmesg dns format free help hwi ifconfig ipdebug kill log ls lsfd memcheck mkdir mount netstat oom partinfo partition ping ping6 pwd reset rm rmdir sem statfs su swtmr sync systeminfo task telnet test tftp touch umount uname watch writeproc
例如注册 `ls`命令
SHELLCMD_ENTRY(ls_shellcmd, CMD_TYPE_EX, "ls", XARGS, (CMD_CBK_FUNC)osShellCmdLs)
需在链接选项中添加链接该新增命令项参数,具体在liteos_tables_ldflags.mk文件的LITEOS_TABLES_LDFLAGS项下添加-uls_shellcmd。至于SHELLCMD_ENTRY是如何实现的在链接阶段的注册,请自行翻看 (内联汇编篇) ,有详细说明实现细节.
- 动态命令方式,运行时处理
动态注册命令方式一般用在用户命令注册,具体实现代码如下:
osCmdReg(CMD_TYPE_EX, "ls", XARGS, (CMD_CBK_FUNC)osShellCmdLs){// ....//5.正式创建命令,挂入链表return OsCmdItemCreate(cmdType, cmdKey, paraNum, cmdProc);//不存在就注册命令}//创建一个命令项,例如 chmodSTATIC UINT32 OsCmdItemCreate(CmdType cmdType, const CHAR *cmdKey, UINT32 paraNum, CmdCallBackFunc cmdProc){CmdItem *cmdItem = NULL;CmdItemNode *cmdItemNode = NULL;//1.构造命令节点过程cmdItem = (CmdItem *)LOS_MemAlloc(m_aucSysMem0, sizeof(CmdItem));if (cmdItem == NULL) {return OS_ERRNO_SHELL_CMDREG_MEMALLOC_ERROR;}(VOID)memset_s(cmdItem, sizeof(CmdItem), '\0', sizeof(CmdItem));cmdItemNode = (CmdItemNode *)LOS_MemAlloc(m_aucSysMem0, sizeof(CmdItemNode));if (cmdItemNode == NULL) {(VOID)LOS_MemFree(m_aucSysMem0, cmdItem);return OS_ERRNO_SHELL_CMDREG_MEMALLOC_ERROR;}(VOID)memset_s(cmdItemNode, sizeof(CmdItemNode), '\0', sizeof(CmdItemNode));cmdItemNode->cmd = cmdItem; //命令项 cmdItemNode->cmd->cmdHook = cmdProc;//回调函数 osShellCmdLscmdItemNode->cmd->paraNum = paraNum;//`777`,'/home'cmdItemNode->cmd->cmdType = cmdType;//关键字类型cmdItemNode->cmd->cmdKey = cmdKey; //`chmod`//2.完成构造后挂入全局链表(VOID)LOS_MuxLock(&g_cmdInfo.muxLock, LOS_WAIT_FOREVER);OsCmdAscendingInsert(cmdItemNode);//按升序方式插入g_cmdInfo.listNum++;//命令总数增加(VOID)LOS_MuxUnlock(&g_cmdInfo.muxLock);return LOS_OK;}
第二步 解析 | ShellTask
//shell 服务端任务初始化,这个任务负责解析和执行命令
LITE_OS_SEC_TEXT_MINOR UINT32 ShellTaskInit(ShellCB *shellCB)
{CHAR *name = NULL;TSK_INIT_PARAM_S initParam = {0};//输入Shell命令的两种方式if (shellCB->consoleID == CONSOLE_SERIAL) { //通过串口工具name = SERIAL_SHELL_TASK_NAME;} else if (shellCB->consoleID == CONSOLE_TELNET) {//通过远程工具name = TELNET_SHELL_TASK_NAME;} else {return LOS_NOK;}initParam.pfnTaskEntry = (TSK_ENTRY_FUNC)ShellTask;//任务入口函数,主要是解析shell命令initParam.usTaskPrio = 9; /* 9:shell task priority */initParam.auwArgs[0] = (UINTPTR)shellCB;initParam.uwStackSize = 0x3000;initParam.pcName = name;initParam.uwResved = LOS_TASK_STATUS_DETACHED;(VOID)LOS_EventInit(&shellCB->shellEvent);//初始化事件,以事件方式通知任务解析命令return LOS_TaskCreate(&shellCB->shellTaskHandle, &initParam);//创建任务
}
LITE_OS_SEC_TEXT_MINOR UINT32 ShellTask(UINTPTR param1,UINTPTR param2,UINTPTR param3,UINTPTR param4)
{UINT32 ret;ShellCB *shellCB = (ShellCB *)param1;(VOID)param2;(VOID)param3;(VOID)param4;while (1) {PRINTK("\nOHOS # ");//读取shell 输入事件 例如: cat weharmony.net 命令ret = LOS_EventRead(&shellCB->shellEvent,0xFFF, LOS_WAITMODE_OR | LOS_WAITMODE_CLR, LOS_WAIT_FOREVER);if (ret == SHELL_CMD_PARSE_EVENT) {//获得解析命令事件ShellCmdProcess(shellCB);//处理命令 } else if (ret == CONSOLE_SHELL_KEY_EVENT) {//退出shell事件break;}}OsShellKeyDeInit((CmdKeyLink *)shellCB->cmdKeyLink);//OsShellKeyDeInit((CmdKeyLink *)shellCB->cmdHistoryKeyLink);(VOID)LOS_EventDestroy(&shellCB->shellEvent);//注销事件(VOID)LOS_MemFree((VOID *)m_aucSysMem0, shellCB);//释放shell控制块return 0;
}
解读
-
任务优先级和 客户端任务 一样同为
9 -
指定内核栈大小为
0x3000 = 12K,因任务负责命令的解析和执行,所以需要更大的内核空间. -
任务的入口函数
ShellTask,一个死循环在以LOS_WAIT_FOREVER方式死等事件发生.SHELL_CMD_PARSE_EVENT通知开始解析事件,该事件由 客户端任务ShellEntry检测到回车键时发出.
STATIC VOID ShellNotify(ShellCB *shellCB){(VOID)LOS_EventWrite(&shellCB->shellEvent, SHELL_CMD_PARSE_EVENT);}
* `CONSOLE_SHELL_KEY_EVENT` 收到 `exit`命令时将发出该事件,退出`shell`回收资源
- 层层跟进
ShellCmdProcess,解析出命令项和参数内容,最终跑到OsCmdExec中遍历 已注册的命令表,找出命令对应的函数完成回调.
LITE_OS_SEC_TEXT_MINOR UINT32 OsCmdExec(CmdParsed *cmdParsed, CHAR *cmdStr){UINT32 ret;CmdCallBackFunc cmdHook = NULL;CmdItemNode *curCmdItem = NULL;UINT32 i;const CHAR *cmdKey = NULL;if ((cmdParsed == NULL) || (cmdStr == NULL) || (strlen(cmdStr) == 0)) {return (UINT32)OS_ERROR;}ret = OsCmdParse(cmdStr, cmdParsed);//解析出命令关键字,参数if (ret != LOS_OK) {goto OUT;}//遍历命令注册全局链表LOS_DL_LIST_FOR_EACH_ENTRY(curCmdItem, &(g_cmdInfo.cmdList.list), CmdItemNode, list) {cmdKey = curCmdItem->cmd->cmdKey;if ((cmdParsed->cmdType == curCmdItem->cmd->cmdType) &&(strlen(cmdKey) == strlen(cmdParsed->cmdKeyword)) &&(strncmp(cmdKey, (CHAR *)(cmdParsed->cmdKeyword), strlen(cmdKey)) == 0)) {//找到命令的回调函数 例如: ls <-> osShellCmdLscmdHook = curCmdItem->cmd->cmdHook;break;}}ret = OS_ERROR;if (cmdHook != NULL) {//执行命令,即回调函数ret = (cmdHook)(cmdParsed->paramCnt, (const CHAR **)cmdParsed->paramArray);}OUT:for (i = 0; i < cmdParsed->paramCnt; i++) {//无效的命令要释放掉保存参数的内存if (cmdParsed->paramArray[i] != NULL) {(VOID)LOS_MemFree(m_aucSysMem0, cmdParsed->paramArray[i]);cmdParsed->paramArray[i] = NULL;}}return (UINT32)ret;}
第三步 | 执行
想知道有哪些系统shell命令,可以搜索关键词SHELLCMD_ENTRY拿到所有通过静态方式注册的命令.

其中有网络的,进程的,任务的,内存的 等等,此处列出几个常用的shell命令的实现.
ls 命令
SHELLCMD_ENTRY(ls_shellcmd, CMD_TYPE_EX, "ls", XARGS, (CmdCallBackFunc)osShellCmdLs);/*******************************************************
命令功能
ls命令用来显示当前目录的内容。命令格式
ls [path]path为空时,显示当前目录的内容。
path为无效文件名时,显示失败,提示:
ls error: No such directory。
path为有效目录路径时,会显示对应目录下的内容。使用指南
ls命令显示当前目录的内容。
ls可以显示文件的大小。
proc下ls无法统计文件大小,显示为0。*******************************************************/
int osShellCmdLs(int argc, const char **argv)
{char *fullpath = NULL;const char *filename = NULL;int ret;char *shell_working_directory = OsShellGetWorkingDirtectory();//获取当前工作目录if (shell_working_directory == NULL){return -1;}ERROR_OUT_IF(argc > 1, PRINTK("ls or ls [DIRECTORY]\n"), return -1);if (argc == 0)//木有参数时 -> #ls {ls(shell_working_directory);//执行ls 当前工作目录return 0;}filename = argv[0];//有参数时 -> #ls ../harmony or #ls /no such file or directoryret = vfs_normalize_path(shell_working_directory, filename, &fullpath);//获取全路径,注意这里带出来fullpath,而fullpath已经在内核空间ERROR_OUT_IF(ret < 0, set_err(-ret, "ls error"), return -1);ls(fullpath);//执行 ls 全路径free(fullpath);//释放全路径,为啥要释放,因为fullpath已经由内核空间分配return 0;
}
task 命令
SHELLCMD_ENTRY(task_shellcmd, CMD_TYPE_EX, "task", 1, (CmdCallBackFunc)OsShellCmdDumpTask);LITE_OS_SEC_TEXT_MINOR UINT32 OsShellCmdDumpTask(INT32 argc, const CHAR **argv)
{UINT32 flag = 0;
#ifdef LOSCFG_KERNEL_VMflag |= OS_PROCESS_MEM_INFO;
#endifif (argc >= 2) { /* 2: The task shell name restricts the parameters */goto TASK_HELP;}if (argc == 1) {if (strcmp("-a", argv[0]) == 0) {flag |= OS_PROCESS_INFO_ALL;} else if (strcmp("-i", argv[0]) == 0) {if (!OsShellShowTickRespo()) {return LOS_OK;}goto TASK_HELP;} else if (strcmp("-t", argv[0]) == 0) {if (!OsShellShowSchedParam()) {return LOS_OK;}goto TASK_HELP;} else {goto TASK_HELP;}}return OsShellCmdTskInfoGet(OS_ALL_TASK_MASK, NULL, flag);TASK_HELP:PRINTK("Unknown option: %s\n", argv[0]);PRINTK("usage: task or task -a\n");return LOS_NOK;
}
cat 命令
SHELLCMD_ENTRY(cat_shellcmd, CMD_TYPE_EX, "cat", XARGS, (CmdCallBackFunc)osShellCmdCat);/*****************************************************************
cat用于显示文本文件的内容。cat [pathname]
cat weharmony.txt
*****************************************************************/
int osShellCmdCat(int argc, const char **argv)
{char *fullpath = NULL;int ret;unsigned int ca_task;struct Vnode *vnode = NULL;TSK_INIT_PARAM_S init_param;char *shell_working_directory = OsShellGetWorkingDirtectory();//显示当前目录 pwdif (shell_working_directory == NULL){return -1;}ERROR_OUT_IF(argc != 1, PRINTK("cat [FILE]\n"), return -1);ret = vfs_normalize_path(shell_working_directory, argv[0], &fullpath);//由相对路径获取绝对路径ERROR_OUT_IF(ret < 0, set_err(-ret, "cat error"), return -1);VnodeHold();ret = VnodeLookup(fullpath, &vnode, O_RDONLY);if (ret != LOS_OK){set_errno(-ret);perror("cat error");VnodeDrop();free(fullpath);return -1;}if (vnode->type != VNODE_TYPE_REG){set_errno(EINVAL);perror("cat error");VnodeDrop();free(fullpath);return -1;}VnodeDrop();(void)memset_s(&init_param, sizeof(init_param), 0, sizeof(TSK_INIT_PARAM_S));init_param.pfnTaskEntry = (TSK_ENTRY_FUNC)osShellCmdDoCatShow;init_param.usTaskPrio = CAT_TASK_PRIORITY; //优先级10init_param.auwArgs[0] = (UINTPTR)fullpath; //入口参数init_param.uwStackSize = CAT_TASK_STACK_SIZE;//内核栈大小init_param.pcName = "shellcmd_cat"; //任务名称init_param.uwResved = LOS_TASK_STATUS_DETACHED | OS_TASK_FLAG_SPECIFIES_PROCESS;init_param.processID = 2; /* 2: kProcess */ //内核任务ret = (int)LOS_TaskCreate(&ca_task, &init_param);//创建任务显示cat内容if (ret != LOS_OK){free(fullpath);}return ret;
}
你能看明白这些命令的底层实现吗? 如果看明白了,可能会不由得发出 原来如此 的感叹!
鸿蒙全栈开发全新学习指南
也为了积极培养鸿蒙生态人才,让大家都能学习到鸿蒙开发最新的技术,针对一些在职人员、0基础小白、应届生/计算机专业、鸿蒙爱好者等人群,整理了一套纯血版鸿蒙(HarmonyOS Next)全栈开发技术的学习路线【包含了大厂APP实战项目开发】。
本路线共分为四个阶段:
第一阶段:鸿蒙初中级开发必备技能

第二阶段:鸿蒙南北双向高工技能基础:gitee.com/MNxiaona/733GH

第三阶段:应用开发中高级就业技术

第四阶段:全网首发-工业级南向设备开发就业技术:gitee.com/MNxiaona/733GH

《鸿蒙 (Harmony OS)开发学习手册》(共计892页)
如何快速入门?
1.基本概念
2.构建第一个ArkTS应用
3.……

开发基础知识:gitee.com/MNxiaona/733GH
1.应用基础知识
2.配置文件
3.应用数据管理
4.应用安全管理
5.应用隐私保护
6.三方应用调用管控机制
7.资源分类与访问
8.学习ArkTS语言
9.……

基于ArkTS 开发
1.Ability开发
2.UI开发
3.公共事件与通知
4.窗口管理
5.媒体
6.安全
7.网络与链接
8.电话服务
9.数据管理
10.后台任务(Background Task)管理
11.设备管理
12.设备使用信息统计
13.DFX
14.国际化开发
15.折叠屏系列
16.……

鸿蒙开发面试真题(含参考答案):gitee.com/MNxiaona/733GH

鸿蒙入门教学视频:

美团APP实战开发教学:gitee.com/MNxiaona/733GH

写在最后
- 如果你觉得这篇内容对你还蛮有帮助,我想邀请你帮我三个小忙:
- 点赞,转发,有你们的 『点赞和评论』,才是我创造的动力。
- 关注小编,同时可以期待后续文章ing🚀,不定期分享原创知识。
- 想要获取更多完整鸿蒙最新学习资源,请移步前往小编:
gitee.com/MNxiaona/733GH

相关文章:
鸿蒙内核源码分析(Shell解析篇) | 应用窥视内核的窗口
系列篇从内核视角用一句话概括shell的底层实现为:两个任务,三个阶段。其本质是独立进程,因而划到进程管理模块。每次创建shell进程都会再创建两个任务。 客户端任务(ShellEntry): 负责接受来自终端(控制台)敲入的一个个字符&…...
TypeScript在前端项目的渐进式采用策略
渐进式采用 TypeScript 在前端项目中的策略通常包括: 引入TypeScript 如果我们有一个简单的JavaScript模块utils.js,它包含一个函数用于计算两数之和: // utils.js export function add(a, b) {return a b; }首先,我们将文件扩展名改为.t…...
C++容器常用集合(附传送门)
C常用的容器: string容器 C容器——string-CSDN博客 储存字符串的 vector容器 C容器——vector-CSDN博客 向量是动态数组,可以自动扩展以容纳更多元素。 插入和删除元素的时间复杂度取决于操作的位置 tuple容器(元组) C容器…...
基于springboot的校园资料分享平台源码数据库
基于springboot的校园资料分享平台源码数据库 随着信息互联网购物的飞速发展,国内放开了自媒体的政策,一般企业都开始开发属于自己内容分发平台的网站。本文介绍了校园资料分享平台的开发全过程。通过分析企业对于校园资料分享平台的需求,创…...
卷积神经网络(CNN)
大家好,这里是七七,今天来更新关于CNN相关的内容同了。本文是针对CNN原理的说明,但对于小白不是非常友好,建议先掌握神经网络相应知识再进行阅读哦。 一、卷积与互相关 卷积 卷积运算是对两个函数进行的一种数学运算,…...
Linux入门攻坚——22、通信安全基础知识及openssl、CA证书
Linux系统常用的加解密工具:OpenSSL,gpg(是pgp的实现) 加密算法和协议: 对称加密:加解密使用同一个秘钥; DES:Data Encryption Standard,数据加密标准&…...
无障碍Web开发:遵循WCAG标准构建包容性用户体验
无障碍Web开发旨在确保所有用户,无论其身体条件或能力如何,都能轻松、有效地访问和使用Web内容。遵循Web Content Accessibility Guidelines (WCAG) 标准是实现这一目标的关键。以下是一些基于WCAG标准的无障碍Web开发实践,以构建更具包容性的…...
Isaac Sim 3(学习笔记5.8)
Isaac Sim 利用深度学习获取mask掩码图 参考内容 Kubernetes官网 在 Linux 系统中安装并设置 kubectl | Kubernetes准备开始 kubectl 版本和集群版本之间的差异必须在一个小版本号内。 例如:v1.30 版本的客户端能与 v1.29、 v1.30 和 v1.31 版本的控制面通信。 用…...
对象定义成final类型还能改变吗
如果一个Java对象被定义为final类型,那么它的引用不能被改变,但是对象本身的状态仍然可以被修改。这意味着你可以改变final对象的属性,但是不能将其引用指向另一个对象。 例如,下面的代码中,虽然person对象被声明为fi…...
Vue Router 路由hash和history模式
文章目录 hash和history模式区别Hash 模式History 模式 在 Vue 中,路由的两种主要模式是 hash 和 history,默认的路由模式是hash模式。。这两种模式决定了 URL 的外观以及浏览器如何处理 URL 的变化。 hash和history模式区别 特性Hash 模式History 模…...
【xrframe】优化ar相机中加载模型效果
方法一:定义渲染width和height //组件生命周期:在视图层布局完成后执行ready() {const info wx.getSystemInfoSync();//在小程序中同步获取系统信息const width info.windowWidth;//获取屏幕的宽度(单位为物理像素)const heigh…...
解决 SyntaxError: Unexpected token ‘.‘ 报错问题
这个报错一般是编译问题,浏览器的版本过低没通过代码 解决办法: 在package.json文件中加上这个 "browserslist": ["> 1%","last 2 versions","not dead","not ie < 6","Android > 4&…...
谷歌插件V3知识点
1.background.js与content.js与popup.js对比: background.js 生命周期:一开始就执行,最早执行且一直执行; 作用:放置全局的、需要一直运行的代码,权限非常高几乎调用所有Chrome api,还可以发起跨域请求; content.js 生…...
webrtc windows 编译,以及peerconnection_client
webrtc windows环境编译,主要参考webrtc官方文档,自备梯子 depot tools 安装 Install depot_tools 因为我用的是windows,这里下载bundle 的安装包,然后直接解压,最后设置到环境变量PATH。 执行gn等命令不报错&…...
geotrust企业通配符证书2990
随着时代的变化,人们获取信息的方式由报纸、书籍变为手机、电脑,因此很多企事业单位用户开始在互联网中创建网站来进行宣传,吸引客户。为了维护网站安全环境,保护客户数据,企事业单位也开始使用SSL数字证书,…...
网络安全科普:保护你的数字生活
# 网络安全科普:保护你的数字生活 ## 引言 在数字化时代,网络安全已成为每个人都必须面对的问题。从个人隐私保护到金融交易安全,网络的安全性直接关系到我们的日常生活。因此,普及网络安全知识,提高公众的网络安全意…...
Java实战:递归查找指定后缀名的文件
在日常的软件开发中,经常需要处理文件操作。假设我们有一个需求:从一个包含大量JSON文件的文件夹中提取出所有的JSON文件以进行进一步处理。本文将介绍如何利用Java编写一个高效的方法来递归查找指定后缀名的文件。 代码实现: import java.i…...
Linux 操作系统网络编程1
目录 1、网络编程 1.1 OSI 网络七层模型 1.1.1 OSI 参考模型 1.1.2 网络数据传输过程 2 传输层通信协议 2.1 TCP 2.1.1 TCP的3次握手过程 2.1.2 TCP四次挥手过程 2.2 UDP 3 网络编程的IP地址 4 端口 5 套接字 1、网络编程 1.1 OSI 网络七层模型 1.1.1 OSI 参考模型…...
future wait_for()成员、shared_future
future wait_for()成员 wait_for():等待其异步操作操作完成或者超出等待,用于检查异步操作的状态。wait_for()可以接受一个std::chrono::duration类型的参数,它表示等待的最大时间,会返回一个std::future_status枚举值࿰…...
C++ list介绍(迭代器失效)
一、常用接口 reverse逆置 sort排序(默认升序) 仿函数greater<int> merge合并,可以全部合并,也可以一部分合并 unique:去重(先排序,再去重) remove:删除e值&#…...
政务许可场景钓鱼邮件攻击机理与防御体系研究 —— 基于美国克恩县预警事件
摘要 2026 年 5 月,美国加利福尼亚州克恩县(Kern County)官方发布安全预警,披露针对Accela 政务许可申报平台用户的定向钓鱼邮件攻击。攻击者伪装成县政务部门,以 “许可审核费”“紧急支付” 等名义发送伪造账单邮件&…...
AI率总超标?2026年AI论文平台排行榜权威发布,轻松定稿不是梦!
写论文效率低、熬夜赶稿、查重总不通过?别慌!2026 年最新 AI 论文写作工具合集来了,覆盖选题、大纲、初稿、润色、降重、格式、文献引用全流程,帮你精准匹配最适合的学术助手,彻底告别论文内耗!Ἴ…...
Windows缩略图加载太慢?这款智能预加载工具让文件浏览快如闪电
Windows缩略图加载太慢?这款智能预加载工具让文件浏览快如闪电 【免费下载链接】WinThumbsPreloader-V2 WinThumbsPreloader is a powerful open source tool for quickly preloading thumbnails in Windows Explorer. 项目地址: https://gitcode.com/gh_mirrors/…...
告别熬夜做答辩 PPT!用 paperxie 一键把毕业论文转成专业演示稿
paperxie-免费查重复率aigc检测/开题报告/毕业论文/智能排版/文献综述/AI PPThttps://www.paperxie.cn/ppt/createhttps://www.paperxie.cn/ppt/create 谁写毕业论文没被答辩 PPT 搞崩过心态?对着万字论文抠重点、调排版、找模板,半天时间耗在「做 PPT」…...
个人开发者如何通过TaoToken以更低成本体验多种主流大模型
🚀 告别海外账号与网络限制!稳定直连全球优质大模型,限时半价接入中。 👉 点击领取海量免费额度 个人开发者如何通过TaoToken以更低成本体验多种主流大模型 对于预算有限的个人开发者和学生而言,直接接入和使用多个主…...
轴承‘健康体检’新思路:不用复杂公式,5步教你用CNN从振动信号中‘看’出故障先兆
轴承健康监测:用CNN像AI医生一样"听诊"振动信号 想象一下,医生通过听诊器捕捉心跳的微妙变化,就能预判潜在的健康风险。在工业设备的"健康管理"中,轴承的振动信号就像它的"心跳",而卷积…...
LVGL 8.x 实战:搞定Label点击、背景色和文字对齐的3个高频难题
LVGL 8.x实战:攻克Label交互、样式与布局的三大核心痛点 在嵌入式UI开发领域,LVGL以其轻量级和高度可定制性成为众多开发者的首选。但当我们真正开始构建第一个界面时,往往会遇到一些看似简单却令人抓狂的问题——为什么Label不能点击&#…...
遥感图像处理实战:用Python+OpenCV实现同态滤波与小波变换去薄云(附完整代码与效果对比)
遥感图像去云实战:Python实现同态滤波与小波变换的深度对比 薄云覆盖是遥感图像处理中的常见挑战,它会降低图像对比度、模糊地物细节,直接影响后续的地物分类和环境监测精度。本文将带您用Python实现两种经典的去云算法——同态滤波与小波变换…...
在Blender中创建逼真流体模拟:FLIP Fluids插件完全指南
在Blender中创建逼真流体模拟:FLIP Fluids插件完全指南 【免费下载链接】Blender-FLIP-Fluids The FLIP Fluids addon is a tool that helps you set up, run, and render high quality liquid fluid effects all within Blender, the free and open source 3D crea…...
抖音无水印视频下载技术深度解析:双架构设计与性能优化方案
抖音无水印视频下载技术深度解析:双架构设计与性能优化方案 【免费下载链接】douyin_downloader 抖音短视频无水印下载 win编译版本下载:https://www.lanzous.com/i9za5od 项目地址: https://gitcode.com/gh_mirrors/dou/douyin_downloader 抖音无…...
