首页 文章 精选 留言 我的

精选列表

搜索[HarmonyOS SDK],共10000篇文章
优秀的个人博客,低调大师

开源日报 | 下一个AI之城;ChromeOS“安卓化”;HarmonyOS超越iOS;Stable Diffusion 3 Medium开源;计算机专业还值得报考吗?

欢迎阅读 OSCHINA 编辑部出品的开源日报,每天更新一期。 # 2024.6.13 今日要闻 Stable Diffusion 3 Medium 正式开源 Stability AI宣布Stable Diffusion 3 Medium 现已开源,是 Stable Diffusion 3 系列中最新、最先进的文本生成图像 AI 模型 —— 官方声称是 “迄今为止最先进的开源模型”,其性能甚至超过了 Midjourney 6。 SD3 Medium 可以根据用户输入的文本描述,重点克服了文生图模型中手部和脸部的挑战,生成足以乱真的的图像。SD3 Medium 还利用其底层的 Diffusion Transformer 架构,高精度地整合了文字元素。 专为手机设计的最强高速推理引擎 PowerInfer-2 PowerInfer-2 是专为智能手机设计的高度优化的推理框架。PowerInfer-2 最多支持 Mixtral 47B MoE 模型,实现每秒 11.68 个令牌的惊人速度,比其它最先进的框架快 22 倍。即使对于 7B 型号,仅将 FFN 权重的 50% 放置在手机上,PowerInfer-2 仍然保持最先进的速度! ChromeOS 逐渐“安卓化” 谷歌在博客透露称,ChromeOS 底层将更广泛地与 Android 共用同样的技术栈。 为了继续以更快、更大规模的方式向用户推出新的 Google AI 功能,我们将采用部分 Android 堆栈(例如 Android Linux 内核和 Android 框架)作为 ChromeOS 基础的一部分。 将基于 Android 的技术栈引入 ChromeOS 将使我们能够加快 ChromeOS 核心的 AI 创新步伐,简化工程工作,并帮助手机和配件等不同设备更好地与 Chromebook 配合使用。 华为鸿蒙OS一季度首次超越苹果iOS,成中国第二大手机操作系统 根据研究机构Counterpoint Research发布的最新数据,2024年第一季度,华为鸿蒙OS在中国市场超越苹果iOS,这意味着,鸿蒙OS已成中国第二大操作系统。从全球手机系统市场份额来看,安卓和iOS同比均下降1%,而鸿蒙OS的全球份额从2%翻了一番,达到4%。 今日观察 社交观察 计算机专业还值得报考吗 如果简单的回答是:值得报。但更长的答案是:不是值不值得报的问题,而是考上了应该怎么学的问题。 因为在AI时代,掌握计算机理论肯定没有坏处。但是如果在计算机专业只学计算机就意义不大了(当然,如果是天才选手,目标是要把transformer架构拉下马的除外),但是在计算机的基础上,再修一个行业技能专业意义很大。因为AI的价值,未来一定在应用落地。计算机+传统行业。 计算机专业以后更多将是一种语言能力,而语言需要在具体的交流场景中(也就是某个行业),才能更大发挥作用,每个人都应该努力成为一个双语者。 - 微博高飞 Apple Intelligence 背后的模型分成三层 苹果对于 Apple Intelligence 背后技术的介绍,他们的模型分成三层: 1. 本地模型 这部分包含语言模型和扩散模型,另外还有用来做 RAG 的 Semantic Index (语义索引)和 App Intents Toolbox(应用意图工具箱)。 其中语言模型是 3B 的小模型,并且针对一系列任务微调过,比如说摘要、润色、回复邮件等,在这些微调模型权重之上有个适配器,可以根据任务来选择最合适的权重,所以虽然只有 3B,但是能力不弱。 2. 私有云计算(Private Cloud Compute) 对于本地模型满足不了要求的,会传到云端运算。并且苹果在安全性上做了很多工作,对于每一次请求,用户的设备会和私有云计算集群建立一个端到端加密的连接。只有被选择的集群才能解密这些请求数据,数据在返回响应后不会被保留,Apple 也无法访问。 以苹果的口碑,对于这个安全架构我还是相信的。 3. 第三方 LLM 这个视频中没有提及,综合一些其他信息,像一些 Siri 的知识问答、聊天,是接入的外部模型,比如目前接入的有 OpenAI 的 GPT-4o,但未来肯定会接入更多家,并且不同国家地区的 LLM 服务商可能有所不能,比如国内肯定不会用 ChatGPT,至于哪一家还没有宣布。 - 微博宝玉xp iPhone的安卓味越来越浓 其实12年前iPhone4还是4s时代就可以通话录音了,只要越狱后在Cydia里搜索到AudioRecorder就可以通话录音了,只不过不越狱的IOS没这个功能。 相比之下,当然是安卓更方便,毕竟开源,各家开启的方式都很方便,像魅族Flyme是可以自动开启录音,还可以指定联系人才开启录音,iPhone现在有通话录音了,问题居然还会通知对方,那多尴尬啊??? - 即刻科技数码秀 导出微信聊天记录的开源工具 这个memotrace太好用了,我刚才试了一下,备份一个1.4G的微信群聊,四分钟,导出所有文本、图片、表情包和系统信息后只有18M,然后RAR压缩后只有2M!就是说其他99.8%的微信空间都是垃圾冗余。而且导出之后的HTML是按照页面总数和月份分类好的,占用内存非常小,可以在任何浏览器上读取。 ​​​ github.com/LC044/WeChatMsg/releases - 微博失眠狸 那个团子和Stable Diffusion的1000天 如果你昨夜看了如期开源的Stable Diffusion3 Medium,会发现Model Card上3个名字,有2个似曾相识于中文区。Dango233和huoju都是亲身参与SD3训练的开发者,他们从Disco Diffusion时期(2021)开始参与图像生成,1000多天,见证社区一路波澜壮阔。 SD3能顺利开放的波折和他们的力争此刻按下不表,总之二位是开源真正的热爱和实践者。我们的Diffuseum也非常感谢他们作为创立成员,给我们以及中文社区提供的技术支持和信心。 - 微信Latent Cat 媒体观察 吴恩达开源了一个机器翻译智能体项目 在研究团队有限的测试中,吴恩达团队开源的翻译智能体有时能够与领先的商业提供商进行同等水平的竞争,有时则不如它们。但它仍提供了一个高度可控的翻译系统,只需简单更改 prompt,使用者就可以指定语气(正式 / 非正式)、地区变体(例如:使用者想要在西班牙本地说的西班牙语,还是在拉丁美洲说的),并确保术语的翻译一致性(通过提供词汇表)。这个应用程序虽然目前仍稍显稚嫩,但鉴于反思工作流已经展现出不错的成果,吴恩达认为智能体翻译仍有很大的提升空间。 - 机器之心 被指全军覆没?中国软件行业遭遇「季度寒冬」 | BUG 快牛云科技创始人周海鹏总结道:“需求侧本身能力还驾驭不了数字化,人才还需要升级。供给侧本身很多时候半懂不懂,为了大单不顾一切,反过来伤害了客户,加上现在甲方资金紧张。”这些因素的综合,成为当下国内头部软件厂商业绩惨淡的关键。 - 新浪科技 电商之外,阿里的另一场反击! 被马云反复强调的AI,正悄然开启阿里巴巴的新篇章。这不但体现在它正加速电商业务的AI变革,也体现在它对中国AI初创公司拔尖者包圆式的投资。业内甚至有句玩笑话: “如果你想投资中国AI初创公司,最好的办法就是去买阿里巴巴的股票。” - 华商韬略 周鸿祎被AI创作者索赔1元 使用“AI重绘”素材算不算侵权? “对于360此次图片使用之争,我希望该判例能够形成一个国内相关的指导意见。落实到个体上,如何在现有法律框架下保护原创,尊重知识产权,同时又不影响人工智能行业发展,是一个非常难的课题。” - 新京报 AI与“粉红诱惑” 声音打通的是无数个场,游戏的、带货的、教育的等等,最后抵达的是用户。在大模型时代,把声音功能前置是一种典型的产品思维,这意味着更低的门槛、更高效的交互方式以及更庞大的用户群体。 - 光子星球 硅谷之后,谁是下一个AI之城? 已经很少有一个机会能让全球众多城市都跃跃欲试了。到底哪个城市能抓住机会?谁能抓到最大的机会?我们的初步调查表明,在这种全球影响力竞争中,区域竞争其实比全球竞争更激烈。在竞争全球用户之前,每个城市及其公司都需要先角逐人才。而在人才流动上,全球化仍然要让位于区域化。其次,对于学术资源深厚的城市,每个大厂都想去设办公室、抢夺人才,但这对当地城市不见得是好事。最后,基础技术不是一切,产业和文化具有多样性,才能支撑更繁荣的机会。 - 第一财经YiMagazine 美图不想在文生视频领域和巨头们“硬碰硬” 美图试图在投入和盈利之间寻求平衡。“搞模型军备竞赛不是美图的核心战略,我们会在保证应用竞争力的前提下,控制模型的投入。”他还强调,过去很长时间美图都是常年亏损,所以会更看重落地场景和商业模式。” - 界面 今日推荐 开源项目 skylot/jadx https://github.com/skylot/jadx JADX 是一个Dex 到 Java 的反编译器,用于从 Android Dex 和 Apk 文件生成 Java 源代码。JADX 有命令行和 GUI 两个版本。 每日一博 Java 开发必读,谈谈对 Spring IOC 与 AOP 的理解 IOC 和 AOP 是 Spring 中的两个核心的概念。 IOC(Inverse of Control)控制反转,也可以称为依赖倒置。所谓依赖,从程序的角度看,就是比如 A 要调用 B 的方法,那么 A 就依赖于 B,反正 A 要用到 B,则 A 依赖于 B。所谓倒置,你必须理解如果不倒置,会怎么着,因为 A 必须要有 B,才可以调用 B,如果不倒置,意思就是 A 主动获取 B 的实例:B b = new B (),这就是最简单的获取 B 实例的方法(当然还有各种设计模式可以帮助你去获得 B 的实例,比如工厂、Locator 等等),然后你就可以调用 b 对象了。所以,不倒置,意味着 A 要主动获取 B,才能使用 B;到了这里,就应该明白了倒置的意思了。倒置就是 A 要调用 B 的话,A 并不需要主动获取 B,而是由其它人自动将 B 送上门来。 AOP (面向切面编程)的目标就是分离关注点。什么是关注点呢?就是你要做的事,就是关注点。假如你是个公子哥,没啥人生目标,天天就是衣来伸手,饭来张口,整天只知道玩一件事!那么,每天你一睁眼,就光想着吃完饭就去玩(你必须要做的事),但是在玩之前,你还需要穿衣服、穿鞋子、叠好被子、做饭等等等等事情,这些事情就是你的关注点,但是你只想吃饭然后玩,那么怎么办呢?这些事情通通交给别人去干。在你走到饭桌之前,有一个专门的仆人 A 帮你穿衣服,仆人 B 帮你穿鞋子,仆人 C 帮你叠好被子,仆人 D 帮你做饭,然后你就开始吃饭、去玩(这就是你一天的正事),你干完你的正事之后,回来,然后一系列仆人又开始帮你干这个干那个,然后一天就结束了! 开源之声 用户观点 ChromeOS逐渐“安卓化” 观点:1:宁愿折腾那玩意儿也不做去完善 android pc 观点 2:这个是好事,慢慢这个桌面化了。 arm windows 没它啥事了。 话说windows 是该灭亡了。 观点 3:不能用 apk 文件,什么都是扯淡 观点 4:开发者模式开出来就行了 观点 5:我在ChromeOS用Android Studio安装apk 有的架构还是不兼容 观点 6:这系统竟然还有人用 全球销量6000万的开发板:“树莓派”上市了——曾坐马斯克的大火箭上太空 观点 1:可惜现在树莓派既不价格低廉,也不开源开放 观点 2:社区不错,学生党做做毕设合适,就是经销商那副你不买有的是人买的嘴脸,对公采购就算了。 观点 3:原来普通的arm都能上太空 观点 4:现在的树莓派,高不成低不就的。在国产替代的大环境下,媒体要有作为的忽视。 观点 5:用别人的玩儿过,如果做硬件开发折腾和学习,价格不划算。如果用于桌面电脑,看高清视频卡顿,性能又跟不上。总之想玩儿一玩儿不如买个华强北山寨版orange派 观点 6:现在国产开发版一大把,价格低性能还更强 观点 7:老哥给推荐一个国产的,我整一个玩玩 观点 8:orangepi 观点 9:为啥看到留言都是吐槽的?我最近折腾了一个,感觉挺好的,Debian几乎就是原生 Debian,还没遇到软件问题 观点 10:以前:这个便宜,买这个。现在:这个性能好,买这个。 观点 11:树莓派以前还能夸两句,现在价格完全配不上,一开始还搞什么公益不公益的,现在还上市算是装都不装了。 苹果称 Swift 是 C++ 的最佳继任者 观点 1:swift和rust为何不合并? 观点 2:swift支持Linux,那么就可以支持Android native了吗? ---END--- 最后,欢迎扫码下载「开源中国 APP」,阅读海量技术报告、程序员极客分享!

优秀的个人博客,低调大师

| 百篇博客分析HarmonyOS源码 | v45.03

百万汉字注解 >> 精读内核源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding > 百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,主流站点定期更新中< oschina | csdn | harmony > 笔者第一次看到fork时,说是一次调用,两次返回,当时就懵圈了,多新鲜,真的很难理解.因为这足以颠覆了以往对函数的认知, 函数调用还能这么玩,父进程调用一次,父子进程各返回一次.而且只能通过返回值来判断是哪个进程的返回.所以一直有几个问题缠绕在脑海中. fork是什么? 外部如何正确使用它. 为什么要用fork这种设计? fork的本质和好处是什么? 怎么做到的? 调用fork()使得父子进程各返回一次,一个函数不是只能返回一次吗,怎么做到返回两次的,其中到底发生了什么? 为什么pid == 0 代表了是子进程的返回? 为什么父进程不需要返回 0 ? 直到看了linux内核源码后才搞明白了这些问题,但系列篇的定位挖透鸿蒙的内核源码,所以本篇将深入fork函数,从鸿蒙角度去说明白这些问题. 在看本篇之前一定要先看系列篇的其他篇幅.如(任务切换篇,寄存器篇,工作模式篇,系统调用篇 等等),有了这些基础,会很好理解fork的实现过程. fork是什么 先看一个网上经常拿来说fork的一个代码片段. #include <sys/types.h> #include <unistd.h> #include <stdio.h> #include <stdlib.h> int main(void) { pid_t pid; char *message; int n; pid = fork(); if (pid < 0) { perror("fork failed"); exit(1); } if (pid == 0) { message = "This is the child\n"; n = 6; } else { message = "This is the parent\n"; n = 3; } for(; n > 0; n--) { printf(message); sleep(1); } return 0; } pid < 0 fork 失败 pid == 0 fork成功,是子进程的返回 pid > 0 fork成功,是父进程的返回 fork的返回值这样规定是有道理的。fork在子进程中返回0,子进程仍可以调用getpid函数得到自己的进程id,也可以调用getppid函数得到父进程的id。在父进程中用getpid可以得到自己的进程id,然而要想得到子进程的id,只有将fork的返回值记录下来,别无它法。 子进程并没有真正执行fork(),而是内核用了一个很巧妙的方法获得了返回值,并且将返回值硬生生的改写成了0,这是笔者认为fork的实现最精彩的部分. 运行结果 $ ./a.out This is the child This is the parent This is the child This is the parent This is the child This is the parent This is the child $ This is the child This is the child 这个程序的运行过程如下图所示。 解读 fork 是一个系统调用,因此会切换到SVC模式运行.在SVC栈中父进程复制出一个子进程,父进程和子进程的PCB信息相同,用户态代码和数据也相同. 从案例的执行上可以看出,fork 之后的代码父子进程都会执行,即代码段指向(PC寄存器)是一样的.实际上fork只被父进程调用了一次,子进程并没有执行fork函数,但是却获得了一个返回值,pid == 0,这个非常重要.这是本篇说明的重点. 从执行结果上看,父进程打印了三次(This is the parent),因为 n = 3. 子进程打印了六次(This is the child),因为 n = 6. 而子程序并没有执行以下代码: pid_t pid; char *message; int n; 子进程是从pid = fork() 后开始执行的,按理它不会在新任务栈中出现这些变量,而实际上后面又能顺利的使用这些变量,说明父进程当前任务的用户态的数据也复制了一份给子进程的新任务栈中. 被fork成功的子进程跑的首条代码指令是 pid = 0,这里的0是返回值,存放在R0寄存器中.说明父进程的任务上下文也进行了一次拷贝,父进程从内核态回到用户态时恢复的上下文和子进程的任务上下文是一样的,即 PC寄存器指向是一样的,如此才能确保在代码段相同的位置执行. 执行./a.out后 第一条打印的是This is the child说明 fork()中发生了一次调度,CPU切到了子进程的任务执行,sleep(1)的本质在系列篇中多次说过是任务主动放弃CPU的使用权,将自己挂入任务等待链表,由此发生一次任务调度,CPU切到父进程执行,才有了打印第二条的This is the parent,父进程的sleep(1)又切到子进程如此往返,直到 n = 0, 结束父子进程. 但这个例子和笔者的解读只解释了fork是什么的使用说明书,并猜测其中做了些什么,并没有说明为什么要这样做和代码是怎么实现的. 正式结合鸿蒙的源码说清楚为什么和怎么做这两个问题? 为什么是fork fork函数的特点概括起来就是“调用一次,返回两次”,在父进程中调用一次,在父进程和子进程中各返回一次。从上图可以看出,一开始是一个控制流程,调用fork之后发生了分叉,变成两个控制流程,这也就是“fork”(分叉)这个名字的由来了。 系列篇已经写了40+多篇,已经很容易理解一个程序运行起来就需要各种资源(内存,文件,ipc,监控信息等等),资源就需要管理,进程就是管理资源的容器.这些资源相当于干活需要各种工具一样,干活的工具都差不多,实在没必再走流程一一申请,而且申请下来会发现和别人手里已有的工具都一样, 别人有直接拿过来使用它不香吗? 所以最简单的办法就是认个干爹,让干爹拷贝一份干活工具给你.这样只需要专心的干好活(任务)就行了. fork的本质就是copy,具体看代码. fork怎么实现的? //系统调用之fork ,建议去 https://gitee.com/weharmony/kernel_liteos_a_note fork 一下? :P int SysFork(void) { return OsClone(CLONE_SIGHAND, 0, 0);//本质就是克隆 } LITE_OS_SEC_TEXT INT32 OsClone(UINT32 flags, UINTPTR sp, UINT32 size) { UINT32 cloneFlag = CLONE_PARENT | CLONE_THREAD | CLONE_VFORK | CLONE_VM; if (flags & (~cloneFlag)) { PRINT_WARN("Clone dont support some flags!\n"); } return OsCopyProcess(cloneFlag & flags, NULL, sp, size); } STATIC INT32 OsCopyProcess(UINT32 flags, const CHAR *name, UINTPTR sp, UINT32 size) { UINT32 intSave, ret, processID; LosProcessCB *run = OsCurrProcessGet();//获取当前进程 LosProcessCB *child = OsGetFreePCB();//从进程池中申请一个进程控制块,鸿蒙进程池默认64 if (child == NULL) { return -LOS_EAGAIN; } processID = child->processID; ret = OsForkInitPCB(flags, child, name, sp, size);//初始化进程控制块 if (ret != LOS_OK) { goto ERROR_INIT; } ret = OsCopyProcessResources(flags, child, run);//拷贝进程的资源,包括虚拟空间,文件,安全,IPC == if (ret != LOS_OK) { goto ERROR_TASK; } ret = OsChildSetProcessGroupAndSched(child, run);//设置进程组和加入进程调度就绪队列 if (ret != LOS_OK) { goto ERROR_TASK; } LOS_MpSchedule(OS_MP_CPU_ALL);//给各CPU发送准备接受调度信号 if (OS_SCHEDULER_ACTIVE) {//当前CPU core处于活动状态 LOS_Schedule();// 申请调度 } return processID; ERROR_TASK: SCHEDULER_LOCK(intSave); (VOID)OsTaskDeleteUnsafe(OS_TCB_FROM_TID(child->threadGroupID), OS_PRO_EXIT_OK, intSave); ERROR_INIT: OsDeInitPCB(child); return -ret; } ### OsForkInitPCB STATIC UINT32 (UINT32 flags, LosProcessCB *child, const CHAR *name, UINTPTR sp, UINT32 size) { UINT32 ret; LosProcessCB *run = OsCurrProcessGet();//获取当前进程 ret = OsInitPCB(child, run->processMode, OS_PROCESS_PRIORITY_LOWEST, LOS_SCHED_RR, name);//初始化PCB信息,进程模式,优先级,调度方式,名称 == 信息 if (ret != LOS_OK) { return ret; } ret = OsCopyParent(flags, child, run);//拷贝父亲大人的基因信息 if (ret != LOS_OK) { return ret; } return OsCopyTask(flags, child, name, sp, size);//拷贝任务,设置任务入口函数,栈大小 } //初始化PCB块 STATIC UINT32 OsInitPCB(LosProcessCB *processCB, UINT32 mode, UINT16 priority, UINT16 policy, const CHAR *name) { UINT32 count; LosVmSpace *space = NULL; LosVmPage *vmPage = NULL; status_t status; BOOL retVal = FALSE; processCB->processMode = mode; //用户态进程还是内核态进程 processCB->processStatus = OS_PROCESS_STATUS_INIT; //进程初始状态 processCB->parentProcessID = OS_INVALID_VALUE; //爸爸进程,外面指定 processCB->threadGroupID = OS_INVALID_VALUE; //所属线程组 processCB->priority = priority; //进程优先级 processCB->policy = policy; //调度算法 LOS_SCHED_RR processCB->umask = OS_PROCESS_DEFAULT_UMASK; //掩码 processCB->timerID = (timer_t)(UINTPTR)MAX_INVALID_TIMER_VID; LOS_ListInit(&processCB->threadSiblingList);//初始化孩子任务/线程链表,上面挂的都是由此fork的孩子线程 见于 OsTaskCBInit LOS_ListTailInsert(&(processCB->threadSiblingList), &(taskCB->threadList)); LOS_ListInit(&processCB->childrenList); //初始化孩子进程链表,上面挂的都是由此fork的孩子进程 见于 OsCopyParent LOS_ListTailInsert(&parentProcessCB->childrenList, &childProcessCB->siblingList); LOS_ListInit(&processCB->exitChildList); //初始化记录退出孩子进程链表,上面挂的是哪些exit 见于 OsProcessNaturalExit LOS_ListTailInsert(&parentCB->exitChildList, &processCB->siblingList); LOS_ListInit(&(processCB->waitList)); //初始化等待任务链表 上面挂的是处于等待的 见于 OsWaitInsertWaitLIstInOrder LOS_ListHeadInsert(&processCB->waitList, &runTask->pendList); for (count = 0; count < OS_PRIORITY_QUEUE_NUM; ++count) { //根据 priority数 创建对应个数的队列 LOS_ListInit(&processCB->threadPriQueueList[count]); //初始化一个个线程队列,队列中存放就绪状态的线程/task }//在鸿蒙内核中 task就是thread,在鸿蒙源码分析系列篇中有详细阐释 见于 https://my.oschina.net/u/3751245 if (OsProcessIsUserMode(processCB)) {// 是否为用户模式进程 space = LOS_MemAlloc(m_aucSysMem0, sizeof(LosVmSpace));//分配一个虚拟空间 if (space == NULL) { PRINT_ERR("%s %d, alloc space failed\n", __FUNCTION__, __LINE__); return LOS_ENOMEM; } VADDR_T *ttb = LOS_PhysPagesAllocContiguous(1);//分配一个物理页用于存储L1页表 4G虚拟内存分成 (4096*1M) if (ttb == NULL) {//这里直接获取物理页ttb PRINT_ERR("%s %d, alloc ttb or space failed\n", __FUNCTION__, __LINE__); (VOID)LOS_MemFree(m_aucSysMem0, space); return LOS_ENOMEM; } (VOID)memset_s(ttb, PAGE_SIZE, 0, PAGE_SIZE);//内存清0 retVal = OsUserVmSpaceInit(space, ttb);//初始化虚拟空间和进程mmu vmPage = OsVmVaddrToPage(ttb);//通过虚拟地址拿到page if ((retVal == FALSE) || (vmPage == NULL)) {//异常处理 PRINT_ERR("create space failed! ret: %d, vmPage: %#x\n", retVal, vmPage); processCB->processStatus = OS_PROCESS_FLAG_UNUSED;//进程未使用,干净 (VOID)LOS_MemFree(m_aucSysMem0, space);//释放虚拟空间 LOS_PhysPagesFreeContiguous(ttb, 1);//释放物理页,4K return LOS_EAGAIN; } processCB->vmSpace = space;//设为进程虚拟空间 LOS_ListAdd(&processCB->vmSpace->archMmu.ptList, &(vmPage->node));//将空间映射页表挂在 空间的mmu L1页表, L1为表头 } else { processCB->vmSpace = LOS_GetKVmSpace();//内核共用一个虚拟空间,内核进程 常驻内存 } #ifdef LOSCFG_SECURITY_VID status = VidMapListInit(processCB); if (status != LOS_OK) { PRINT_ERR("VidMapListInit failed!\n"); return LOS_ENOMEM; } #endif #ifdef LOSCFG_SECURITY_CAPABILITY OsInitCapability(processCB); #endif if (OsSetProcessName(processCB, name) != LOS_OK) { return LOS_ENOMEM; } return LOS_OK; } //拷贝一个Task过程 STATIC UINT32 OsCopyTask(UINT32 flags, LosProcessCB *childProcessCB, const CHAR *name, UINTPTR entry, UINT32 size) { LosTaskCB *childTaskCB = NULL; TSK_INIT_PARAM_S childPara = { 0 }; UINT32 ret; UINT32 intSave; UINT32 taskID; OsInitCopyTaskParam(childProcessCB, name, entry, size, &childPara);//初始化Task参数 ret = LOS_TaskCreateOnly(&taskID, &childPara);//只创建任务,不调度 if (ret != LOS_OK) { if (ret == LOS_ERRNO_TSK_TCB_UNAVAILABLE) { return LOS_EAGAIN; } return LOS_ENOMEM; } childTaskCB = OS_TCB_FROM_TID(taskID);//通过taskId获取task实体 childTaskCB->taskStatus = OsCurrTaskGet()->taskStatus;//任务状态先同步,注意这里是赋值操作. ...01101001 if (childTaskCB->taskStatus & OS_TASK_STATUS_RUNNING) {//因只能有一个运行的task,所以如果一样要改4号位 childTaskCB->taskStatus &= ~OS_TASK_STATUS_RUNNING;//将四号位清0 ,变成 ...01100001 } else {//非运行状态下会发生什么? if (OS_SCHEDULER_ACTIVE) {//克隆线程发生错误未运行 LOS_Panic("Clone thread status not running error status: 0x%x\n", childTaskCB->taskStatus); } childTaskCB->taskStatus &= ~OS_TASK_STATUS_UNUSED;//干净的Task childProcessCB->priority = OS_PROCESS_PRIORITY_LOWEST;//进程设为最低优先级 } if (OsProcessIsUserMode(childProcessCB)) {//是否是用户进程 SCHEDULER_LOCK(intSave); OsUserCloneParentStack(childTaskCB, OsCurrTaskGet());//拷贝当前任务上下文给新的任务 SCHEDULER_UNLOCK(intSave); } OS_TASK_PRI_QUEUE_ENQUEUE(childProcessCB, childTaskCB);//将task加入子进程的就绪队列 childTaskCB->taskStatus |= OS_TASK_STATUS_READY;//任务状态贴上就绪标签 return LOS_OK; } //把父任务上下文克隆给子任务 LITE_OS_SEC_TEXT VOID OsUserCloneParentStack(LosTaskCB *childTaskCB, LosTaskCB *parentTaskCB) { TaskContext *context = (TaskContext *)childTaskCB->stackPointer; VOID *cloneStack = (VOID *)(((UINTPTR)parentTaskCB->topOfStack + parentTaskCB->stackSize) - sizeof(TaskContext)); //cloneStack指向 TaskContext LOS_ASSERT(parentTaskCB->taskStatus & OS_TASK_STATUS_RUNNING);//当前任务一定是正在运行的task (VOID)memcpy_s(childTaskCB->stackPointer, sizeof(TaskContext), cloneStack, sizeof(TaskContext));//直接把任务上下文拷贝了一份 context->R[0] = 0;//R0寄存器为0,这个很重要, pid = fork() pid == 0 是子进程返回. } 解读 可以看出fork的主体函数是OsCopyProcess,先申请一个干净的PCB,相当于申请一个容器装资源. 初始化这个容器OsForkInitPCB, OsInitPCB 先把容器打扫干净,虚拟空间,地址映射表(L1表),各种链表初始化好,为接下来的内容拷贝做好准备. OsCopyParent把家族基因/关系传递给子进程,谁是你的老祖宗,你的七大姑八大姨是谁都得告诉你知道,这些都将挂到你已经初始化好的链表上. OsCopyTask这个很重要,拷贝父进程当前执行的任务数据给子进程的新任务,系列篇中已经说过,真正让CPU干活的是任务(线程),所以子进程需要创建一个新任务 LOS_TaskCreateOnly来接受当前任务的数据,这个数据包括栈的数据,运行代码段指向,OsUserCloneParentStack将用户态的上下文数据TaskContext拷贝到子进程新任务的栈底位置, 也就是说新任务运行栈中此时只有上下文的数据.而且有最最最重要的一句代码 context->R[0] = 0; 强制性的将未来恢复上下文R0寄存器的数据改成了0, 这意味着调度算法切到子进程的任务后, 任务干的第一件事是恢复上下文,届时R0寄存器的值变成0,而R0=0意味着什么? 同时LR/SP寄存器的值也和父进程的一样.这又意味着什么? 系列篇寄存器篇中以说过返回值就是存在R0寄存器中,A()->B(),A拿B的返回值只认R0的数据,读到什么就是什么返回值,而R0寄存器值等于0,等同于获得返回值为0, 而LR寄存器所指向的指令是pid=返回值, sp寄存器记录了栈中的开始计算的位置,如此完全还原了父进程调用fork()前的运行场景,唯一的区别是改变了R0寄存器的值,所以才有了 pid = 0;//fork()的返回值,注意子进程并没有执行fork(),它只是通过恢复上下文获得了一个返回值. if (pid == 0) { message = "This is the child\n"; n = 6; } 由此确保了这是子进程的返回.这是fork()最精彩的部分.一定要好好理解.OsCopyTask``OsUserCloneParentStack的代码细节.会让你醍醐灌顶,永生难忘. 父进程的返回是processID = child->processID;是子进程的ID,任何子进程的ID是不可能等于0的,成功了只能是大于0. 失败了就是负数 return -ret; OsCopyProcessResources用于赋值各种资源,包括拷贝虚拟空间内存,拷贝打开的文件列表,IPC等等. OsChildSetProcessGroupAndSched设置子进程组和调度的准备工作,加入调度队列,准备调度. LOS_MpSchedule是个核间中断,给所有CPU发送调度信号,让所有CPU发生一次调度.由此父进程让出CPU使用权,因为子进程的调度优先级和父进程是平级,而同级情况下子进程的任务已经插到就绪队列的头部位置 OS_PROCESS_PRI_QUEUE_ENQUEUE排在了父进程任务的前面,所以在没有比他们更高优先级的进程和任务出现之前,下一次被调度到的任务就是子进程的任务.也就是在本篇开头看到的 $ ./a.out This is the child This is the parent This is the child This is the parent This is the child This is the parent This is the child $ This is the child This is the child 以上为fork在鸿蒙内核的整个实现过程,务必结合系列篇其他篇理解,一次理解透彻,终生不忘. 鸿蒙源码百篇博客 往期回顾 v45.03 (fork篇) | fork是如何做到调用一次,返回两次的 ? < csdn | harmony > v44.03 (中断管理篇) | 硬中断的实现<>观察者模式 < csdn | harmony > v43.03 (中断概念篇) | 外人眼中权势滔天的当红海公公 < csdn | harmony > v42.03 (中断切换篇) | 中断切换到底在切换什么? < csdn | harmony > v41.03 (任务切换篇) | 汇编逐行注解分析任务上下文 < csdn | harmony > v40.03 (汇编汇总篇) | 所有的汇编代码都在这里 < csdn | harmony > v39.03 (异常接管篇) | 社会很单纯,复杂的是人 < csdn | harmony > v38.03 (寄存器篇) | ARM所有寄存器一网打尽,不再神秘 < csdn | harmony > v37.03 (系统调用篇) | 全盘解剖系统调用实现过程 < csdn | harmony > v36.03 (工作模式篇) | CPU是韦小宝,有哪七个老婆? < csdn | harmony > v35.03 (时间管理篇) | Tick是操作系统的基本时间单位 < csdn | harmony > v34.03 (原子操作篇) | 是谁在为原子操作保驾护航? < csdn | harmony > v33.03 (消息队列篇) | 进程间如何异步解耦传递大数据 ? < csdn | harmony > v32.03 (CPU篇) | 内核是如何描述CPU的? < csdn | harmony > v31.03 (定时器篇) | 内核最高优先级任务是谁? < csdn | harmony > v30.03 (事件控制篇) | 任务间多对多的同步方案 < csdn | harmony > v29.03 (信号量篇) | 信号量解决任务同步问题 < csdn | harmony > v28.03 (进程通讯篇) | 进程间通讯有哪九大方式? < csdn | harmony > v27.03 (互斥锁篇) | 互斥锁比自旋锁可丰满许多 < csdn | harmony > v26.03 (自旋锁篇) | 真的好想为自旋锁立贞节牌坊! < csdn | harmony > v25.03 (并发并行篇) | 怎么记住并发并行的区别? < csdn | harmony > v24.03 (进程概念篇) | 进程在管理哪些资源? < csdn | harmony > v23.02 (汇编传参篇) | 汇编如何传递复杂的参数? < csdn | harmony > v22.02 (汇编基础篇) | CPU在哪里打卡上班? < csdn | harmony > v21.02 (线程概念篇) | 是谁在不断的折腾CPU? < csdn | harmony > v20.02 (用栈方式篇) | 栈是构建底层运行的基础 < csdn | harmony > v19.02 (位图管理篇) | 为何进程和线程优先级都是32个? < csdn | harmony > v18.02 (源码结构篇) | 内核500问你能答对多少? < csdn | harmony > v17.02 (物理内存篇) | 这样记伙伴算法永远不会忘 < csdn | harmony > v16.02 (内存规则篇) | 内存管理到底在管什么? < csdn | harmony > v15.02 (内存映射篇) | 什么是内存最重要的实现基础 ? < csdn | harmony > v14.02 (内存汇编篇) | 什么是虚拟内存的实现基础? < csdn | harmony > v13.02 (源码注释篇) | 热爱是所有的理由和答案 < csdn | harmony > v12.02 (内存管理篇) | 虚拟内存全景图是怎样的? < csdn | harmony > v11.02 (内存分配篇) | 内存有哪些分配方式? < csdn | harmony > v10.02 (内存主奴篇) | 紫禁城的主子和奴才如何相处? < csdn | harmony > v09.02 (调度故事篇) | 用故事说内核调度 < csdn | harmony > v08.02 (总目录) | 百万汉字注解 百篇博客分析 < csdn | harmony > v07.02 (调度机制篇) | 任务是如何被调度执行的? < csdn | harmony > v06.02 (调度队列篇) | 就绪队列对调度的作用 < csdn | harmony > v05.02 (任务管理篇) | 谁在让CPU忙忙碌碌? < csdn | harmony > v04.02 (任务调度篇) | 任务是内核调度的单元 < csdn | harmony > v03.02 (时钟任务篇) | 触发调度最大的动力来自哪里? < csdn | harmony > v02.02 (进程管理篇) | 进程是内核资源管理单元 < csdn | harmony > v01.09 (双向链表篇) | 谁是内核最重要结构体? < csdn | harmony > 参与贡献 访问注解仓库地址 Fork 本仓库 >> 新建 Feat_xxx 分支 >> 提交代码注解 >> 新建 Pull Request 新建 Issue 喜欢请大方 点赞+关注+收藏 吧 关注「鸿蒙内核源码分析」公众号,百万汉字注解 + 百篇博客分析 => 深挖鸿蒙内核源码 各大站点搜 "鸿蒙内核源码分析" .欢迎转载,请注明出处.

优秀的个人博客,低调大师

鸿蒙内核源码分析(寄存器篇) | arm 37个寄存器一网打尽 , 不再神秘 | 中文注解HarmonyOS源码 | v38.01

百万汉字注解 >> 精读内核源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding > 百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,多站点每日同步更新< oschina | csdn | weharmony > 本篇说清楚寄存器 ARM系列篇基于ARM720T.pdf文档. 读本篇之前建议先读鸿蒙内核源码分析(总目录)arm体系系列篇. 寄存器的本质 寄存器从大一的计算机组成原理就开始听到它,感觉很神秘,如梦如雾多年.揭开本质后才发现,寄存器就是一个32位的存储空间,一个int变量而已,但它的厉害之处在于极高频率的使用,让人不敢相信是怎么做到的,不管再复杂再牛牛的应用程序,电商也好,游戏,直播也罢,到了它这里都变成了有限的十几个寄存器在玩,简直太神奇了. 本篇将清楚说明寄存器的数量和功能,至于它是如何把复杂的上层程序变成了这十几个寄存器来玩?这是编译器的事情,不在讨论范围之内. arm7有37个寄存器,具体看图说明: 这些寄存器不能同时显示,处理器指令状态和工作模式指定哪些寄存器可供使用,图中一一对应. 其中31个通用32位寄存器,系统和用户模式全程复用寄存器,而其余5中异常(或叫特权)模式从R8_* ~ R14_* 的寄存器叫模式专属寄存器. 注意 r8 和 r8_fiq是两个不同的寄存器,名字前缀是为了好记,管理方便,以示同级概念理解.如此凑成了31个寄存器. 其中r13寄存器用于SP寄存器,始终指向栈顶,因为每种工作模式都有独立的运行栈,所以有独立的寄存器去记住各自的栈顶. 同理r14寄存器用于LR寄存器,用于保存模式切换时的切换位置,也是独立存在,说明模式间回跳时并不需要重新给r14_*赋值,只需在跳出去的时候保存即可. 系统和用户模式共用r13(sp)和r14(lr)寄存器,所以在每个子函数的栈帧中都要保存上一个调用它函数的SP和LR值,自己执行完成后要从栈帧中恢复这两个寄存器的值,否则无法界定回去后从哪里开始,从哪里计算偏移位置. r15(pc)寄存器是指向代码段的,所有模式复用的原因是它是共用的,一份代码,你运行与不允许,代码段就在哪里,不增不减. 6个状态寄存器,其中CPSR(1个)和SPSR_*(5个),它们主要用于自运行或发生模式切换后的各种状态保存. CPSR:程序状态寄存器(current program status register) (当前程序状态寄存器),在任何处理器模式下被访问。 SPSR:程序状态保存寄存器(saved program status register),每一种处理器模式下都有一个状态寄存器SPSR,SPSR用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。当特定 的异常中断发生时,这个寄存器用于存放当前程序状态寄存器的内容。在异常中断退出时,可以用SPSR来恢复CPSR。 七种工作模式 关于工作模式在 鸿蒙内核源码分析(总目录)之工作模式篇中有详细,可自行前往查看.此处只简单说明下. 下图来源于 ARM720T.pdf第43页,在ARM体系中,CPU工作在以下七种模式中: 用户模式(usr):属于正常的用户模式,ARM处理器正常的程序执行状态。 快速中断模式(fiq):用于处理快速中断,对高速数据传输或通道处理 外部中断模式(irq):对一般情况下的中断进行处理。 管理模式(svc):属于操作系统使用的保护模式,处理软件中断swi reset。 数据访问终止模式(abt):当数据或指令预取终止时进入该模式,可用于处理存储器故障、实现虚拟存储器和存储器保护。 系统模式(sys):运行具有特权的操作系统任务。 未定义指令中止模式(und):处理未定义的指令陷阱,当未定义的指令执行时进入该模式,可用于支持硬件协处理器的软件仿真。 R0 寄存器 R0是寄存器中的王牌,被称为头号寄存器,通用寄存器中它用的最高频,随便翻段汇编代码都能看到它的影子.鸿蒙开机第一跳指令就是 r0 = 0 reset_vector: //鸿蒙开机代码 /* clear register TPIDRPRW */ mov r0, #0 @r0 = 0 mcr p15, 0, r0, c13, c0, 4 @c0,c13 = 0, C13为进程标识符 含义见 ARM720T.PDF 第64页 /* do some early cpu setup: i/d cache disable, mmu disabled */ @禁用MMU, i/d缓存 mrc p15, 0, r0, c1, c0, 0 @r0 = c1 ,c1寄存器详细解释见第64页 bic r0, #(1<<12) @位清除指令,清除r0的第11位 bic r0, #(1<<2 | 1<<0) @清除第0和2位 ,禁止 MMU和缓存 0位:MMU enable/disable 2位:Cache enable/disable mcr p15, 0, r0, c1, c0, 0 @c1=r0 再看拿自旋锁的汇编代码,这些代码都在系列篇中详细讲解过,可前往鸿蒙内核源码分析(总目录)自行查看. FUNCTION(ArchSpinLock) @非要拿到锁 mov r1, #1 @r1=1 1: @循环的作用,因SEV是广播事件.不一定lock->rawLock的值已经改变了 ldrex r2, [r0] @r0 = &lock->rawLock, 即 r2 = lock->rawLock cmp r2, #0 @r2和0比较 wfene @不相等时,说明资源被占用,CPU核进入睡眠状态 strexeq r2, r1, [r0]@此时CPU被重新唤醒,尝试令lock->rawLock=1,成功写入则r2=0 cmpeq r2, #0 @再来比较r2是否等于0,如果相等则获取到了锁 bne 1b @如果不相等,继续进入循环 dmb @用DMB指令来隔离,以保证缓冲中的数据已经落实到RAM中 bx lr @此时是一定拿到锁了,跳回调用ArchSpinLock函数 R0被潜规则的干了两件事,突出了它的重要性: 第一个参数 由R0保管,当然第二个参数就给R1保管 函数的返回值统一交给R0保管, 例如 a -> b ,b执行完会把返回值给r0,回到a后,a从r0取值,不管取到什么,它就认为这是b的返回值,默认都只认r0保存了返回值,这就是规定. 具体看一个C函数和它的汇编,系列篇也已经讲过. //++++++++++++ square(c -> 汇编)++++++++++++++++++++++++ int square(int a,int b){ return a*b; } square(int, int): sub sp, sp, #8 @sp减去8,意思为给square分配栈空间,只用2个栈空间完成计算 str r0, [sp, #4] @第一个参数入栈 str r1, [sp] @第二个参数入栈 ldr r1, [sp, #4] @取出第一个参数给r1 ldr r2, [sp] @取出第二个参数给r2 mul r0, r1, r2 @执行a*b给R0,返回值的工作一直是交给R0的 add sp, sp, #8 @函数执行完了,要释放申请的栈空间 bx lr @子程序返回,等同于mov pc,lr,即跳到调用处 //++++++++++++ fp(c -> 汇编)++++++++++++++++++++++++ int fp(int b) { int a = 1; return square(a+b,a+b); } fp(int): push {r11, lr} @r11(fp)/lr入栈,保存调用者main的位置 mov r11, sp @r11用于保存sp值,函数栈开始位置 sub sp, sp, #8 @sp减去8,意思为给fp分配栈空间,只用2个栈空间完成计算 str r0, [sp, #4] @先保存参数值,放在SP+4,此时r0中存放的是参数 mov r0, #1 @r0=1 str r0, [sp] @再把1也保存在SP的位置 ldr r0, [sp] @把SP的值给R0 ldr r1, [sp, #4] @把SP+4的值给R1 add r1, r0, r1 @执行r1=a+b mov r0, r1 @r0=r1,用r0,r1传参 bl square(int, int)@先mov lr, pc 再mov pc square(int, int) mov sp, r11 @函数执行完了,要释放申请的栈空间 pop {r11, lr} @弹出r11和lr,lr是专用标签,弹出就自动复制给lr寄存器 bx lr @子程序返回,等同于mov pc,lr,即跳到调用处 这段代码同样适用于理解一下的各个寄存器. fp 寄存器 fp是栈帧寄存器(frame pointer),每个函数都有自己独立的栈,fp标识从哪里开始,指向函数栈的栈底. SP 寄存器 SP:栈指针寄存器(stack pointer),指向函数栈的栈顶,如此 fp 和 sp 就划定了函数栈的范围,函数在运行期间除了动态申请的内存要跑出去玩,其余就在这块空间里玩. LR 寄存器 异常的发生会导致程序正常运行的被打断, 并将控制流转移到相应的异常处理(异常响应),有些异常(fiq、irq)事件处理后,系统还希望能回 到当初异常发生时被打断的源程序断点处继续完成源程序的执行(异常返回),这就需要一种解决方案, 用于记录源程序的断点位置,以便正确的异常返回。 类似的还有子程序的调用和 返回。在主程序中(通过子程序调用指令)调用子程序时,也需要记录下主程序中的调用点位置,以便将来的子程序的返回。 LR:链接寄存器(linked pointer),就是用来解决上述问题的,ARM处理器中使用 R14实现对断点和调用点的记录,即R14用作返回连接寄存器(LR),确保回来知道自己从哪个位置中断,以便继续执行. PC 寄存器 pc:程序计数寄存器(Program Counter Register) 向代码段取指令,指向代码段具体位置,PC寄存器涉及到arm的流水线结构设计,具体在后续流水线篇中详细说明,敬请关注. CPSR 寄存器 CPSR(current program status register)当前程序的状态寄存器 CPSR有4个8位区域:标志域(F)、状态域(S)、扩展域(X)、控制域(C) 32 位的程序状态寄存器可分为4 个域: 位[31:24]为条件标志位域,用f 表示; 位[23:16]为状态位域,用s 表示; 位[15:8]为扩展位域,用x 表示; 位[7:0]为控制位域,用c 表示; CPSR和其他寄存器不一样,其他寄存器是用来存放数据的,都是整个寄存器具有一个含义. 而CPSR寄存器是按位起作用的,也就是说,它的每一位都有专门的含义,记录特定的信息. CPSR的低8位(包括I、F、T和M[4:0])称为控制位,程序无法修改, 除非CPU运行于特权模式下,程序才能修改控制位 N、Z、C、V均为条件码标志位。它们的内容可被算术或逻辑运算的结果所改变, 并且可以决定某条指令是否被执行!意义重大! CPSR的第31位是 N,符号标志位。它记录相关指令执行后,其结果是否为负. 如果为负 N = 1,如果是非负数 N = 0. CPSR的第30位是Z,0标志位。它记录相关指令执行后,其结果是否为0. 如果结果为0.那么Z = 1.如果结果不为0,那么Z = 0. CPSR的第29位是C,进位标志位(Carry)。一般情况下,进行无符号数的运算。 加法运算:当运算结果产生了进位时(无符号数溢出),C=1,否则C=0。 减法运算(包括CMP):当运算时产生了借位时(无符号数溢出),C=0,否则C=1。 CPSR的第28位是V,溢出标志位(Overflow)。在进行有符号数运算的时候, 如果超过了机器所能标识的范围,称为溢出。 MSR{条件} 程序状态寄存器(CPSR 或SPSR)_<域>,操作数 MSR 指令用于将操作数的内容传送到程序状态寄存器的特定域中 示例如下: MSR CPSR,R0 @传送R0 的内容到CPSR MSR SPSR,R0 @传送R0 的内容到SPSR MSR CPSR_c,R0 @传送R0 的内容到CPSR,但仅仅修改CPSR中的控制位域 MRS{条件} 通用寄存器,程序状态寄存器(CPSR 或SPSR) MRS 指令用于将程序状态寄存器的内容传送到通用寄存器中。该指令一般用在以下两种情况: 1) 当需要改变程序状态寄存器的内容时,可用MRS 将程序状态寄存器的内容读入通用寄存器,修改后再写回程序状态寄存器。 2) 当在异常处理或进程切换时,需要保存程序状态寄存器的值,可先用该指令读出程序状态寄存器的值,然后保存。 示例如下: MRS R0,CPSR @传送CPSR 的内容到R0 MRS R0,SPSR @传送SPSR 的内容到R0 @MRS指令是唯一可以直接读取CPSR和SPSR寄存器的指令 SPSR 寄存器 SPSR(saved program status register)程序状态保存寄存器.五种异常模式下一个状态寄存器SPSR,用于保存CPSR的状态,以便异常返回后恢复异常发生时的工作状态。 1、SPSR 为 CPSR 中断时刻的副本,退出中断后,将SPSR中数据恢复到CPSR中。 2、用户模式和系统模式下SPSR不可用,所以SPSR寄存器只有5个 喜欢就大方 点赞+关注+收藏 吧 各大站点搜 "鸿蒙内核源码分析" ,快速找到组织. 百万汉字注解 >> 精读内核源码,中文注解分析, 深挖地基工程,大脑永久记忆,四大码仓每日同步更新< gitee | github | csdn | coding > 百篇博客分析 >> 故事说内核,问答式导读,生活式比喻,表格化说明,图形化展示,多站点每日同步更新< oschina | csdn | weharmony >

优秀的个人博客,低调大师

深度相机全场景应用实战:从工业检测到人形机器人,Python+SDK实现3D视觉感知与智能避障方案

深度相机(Depth Camera)是一类能够同步采集彩色图像与场景深度数据的智能成像设备,也常被称为RGB-D相机。与仅能捕捉二维平面信息的传统摄像头不同,深度相机可以测算画面中每个像素点对应物体的实际距离,最终生成深度图像与三维点云数据,完整还原真实场景的立体结构。

优秀的个人博客,低调大师

《HarmonyOS 第一课之首席专家讲鸿蒙》重磅上线! 首席专家解码鸿蒙底层设计原理,赋能开发者迈向技术新高度

******************************************************************************************************************** ******************************************************************************************************************** ******************************************************************************************************************** ********************************************************************************************************************

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册