【从浅学到熟知Linux】冯诺依曼体系结构及进程概念详谈!
🏠关于专栏:Linux的浅学到熟知专栏用于记录Linux系统编程、网络编程等内容。
🎯每天努力一点点,技术变化看得见
文章目录
- 冯诺依曼体系结构
- 操作系统
- 如何理解管理
- 操作系统概念
- 设计操作系统目的
- 系统调用和库函数概念
- 进程
- 基本概念
- 描述进程-PCB
- 组织进程
- 查看进程
- 通过系统调用获取进程标识符
- 通过系统调用创建进程
冯诺依曼体系结构
我们常见的计算机,像我们日常使用的笔记本、台式机;我们不常见的计算机,如服务器,大部分都遵循冯诺依曼体系结构。
在讨论冯诺依曼体系结构前,我们先来了解一下该结构涉及的5个部分:输入设备、输出设备、存储器、运算器、控制器。(下面给出了这5个组件的举例)
组件名称 | 举例 |
---|---|
输入设备 | 键盘、摄像头、话筒、磁盘、网卡… |
输出设备 | 显示器、音响、磁盘、网卡… |
存储器 | 内存… |
运算器 | 算术运算单元、逻辑运算单元… |
控制器 | 无举例(负责协调外部就绪事件,如将数据拷贝到内存等) |
下图描述的就是冯诺依曼体系结构,其中外部设备(输入、输出设备)在进行数据交互时,都是直接与存储器直接交互。而CPU从存储器直接获取数据或存储数据。在程序需要访问外部设备时,CPU才会与外部设备有间接交互。
为什么CPU不直接与外部设备直接交互呢?大家可能知道木桶效应,整个木桶的盛水量取决于最低的那块木板。在计算机体系结构中也是这样的。
CPU具有非常快的计算速度,而外部设备的速度太慢了。如果CPU直接与外部设备交互,则CPU在需要获取或输出设备时均要等待外部设备,整机效率取决于外部设备的处理速度。
如果我们让外部设备与存储器直接交互,让CPU与存储器直接交互。在CPU进行计算时,存储器可以与多个输入设备交互,当CPU需要数据时,直接从内存中获取即可;如果CPU需要写入数据,则将数据给存储器,再由存储器与输出设备交互即可。这样一来,整机的效率就取决于存储器的处理速度。大大提高了计算机的处理效率。
因此,我们可以得出如下结论:↓↓↓
- CPU读取数据(数据+代码),都是从内存中读取。站在数据的角度,CPU不和外设直接交互
- CPU要处理数据,需要将外设中的数据加载到内存。站在数据的角度,外设直接只和内存打交道
★ps:在冯诺依曼体系结构中,当某个进程需要访问外设时,CPU并不会一直等待外设,而是使用中断的方式将其从CPU上换下来,由其他进程执行。该程序到对应外设上等待外设处理完成后,再向CPU的控制器发送中断信号,表明自己已经处理完成,可以回到CPU上运行。再由控制器来相应的信号、外部事件等。
★ps:计算机中的寄存器的存取效率比磁盘等存储设备速度快,为什么不将整机的存储设备均换成寄存器材质呢?
一方面,寄存器、内存设备掉电易失(没电就没办法存储数据),而磁盘、磁带等设备为磁性存储介质,可以在没电的情况下继续保存出局;另一方面,寄存器、内存价格昂贵,我们当前的计算机普遍是8G左右内存,计算机的价格就已经较为昂贵了,如果计算机将几百G的磁盘换成内存,则一台计算机的价格将比现在的计算机贵上百倍。
★ps:什么叫做IO?从外部设备将数据拷贝到内存就是Input,从内存将数据拷贝到外部设备就是Output,这就是IO。
★ps:为什么程序要运行,必须先将程序加载到内存?这其实就是冯诺依曼体系结构决定的。硬件设备为了提高整机效率,规定了CPU只能从内存读取数据及指令。因此,软件执行必须遵守硬件规定,必须将待执行程序加载到内存。
【举例说明】如果在厦门,要给远在哈尔滨的朋友发送一条消息。
此时我需要使用使用键盘(外部设备)打字,键盘数据被写入存储器中;CPU从存储器中获取键盘数据,确定要怎么传输之后,将CPU处理后的数据放到存储器中;再由存储器将该数据传给网卡;我的网卡与对方的网卡交互之后,对方网卡将获取的数据写入存储器;对方存储器再将数据传给CPU,CPU对传来的数据进行解码等操作,再将解码后的数据存入存储器;由存储器负责将数据传给显示器进行显示。
★关于冯诺依曼体系结构需要强调以下几点:
- 这里的存储器指的就是内存,不考虑缓存的情况
- 这里的CPU能且只能对内存进行读写,不能访问外设(输入、输出设备)
- 外设(输入、输出设备)要输入或输出数据,只能写入内存或从内存中读取
- 在冯诺依曼体系中,所有设备只能和内存打交道(以存储器为中心)
操作系统
如何理解管理
例子1:学校管理
大学里校长是怎么管理成千上午的学生的呢?我们知道,大学里面有辅导员、班长。他们协助校长管理学生,校长不直接与学生打交道,而是通过辅导员和班长来管理学生。
管理学生的本质是对学生数据做管理,也就是对学生的学号、姓名、成绩等等信息做管理。因而,我们可以使用一个结构体来定义一个学生类型,再使用顺序表或者链表来组织学生信息。这种思想叫做“先描述,再组织”。当校长发现某个数据有问题时,他并不是直接找到这个学生,而是让辅导员处理这个数据问题。
从这可知,管理者和被管理者可以不执行交互(沟通),拿到被管理者的核心数据(用于进行管理决策)才是最重要的。
知识点:操作系统如何管理外设
在计算机有个大boss——操作系统,它不直接与外部设备打交道,而是通过驱动程序管理外部设备。操作系统实际管理的就是一组外设的结构体数据的管理(即对数据进行增删查改)。
例子2:银行提供服务
生活中,我们需要到银行存取钱的时候,都需要到柜台窗口办理业务;再由业务人员与内部金库做交互。为什么不能让用户直接进入金库呢?因为,银行无法甄别哪些人是坏人。为了管理方便,直接拒绝用户进入金库,而提供了柜台这种形式的服务。这种方式不仅能给用户提供服务,还保证了银行的安全。
知识点:操作系统提供接口式服务
操作系统与银行类似,它既要给用户提供服务,但又担心用户的非法操作。因此,操作系统提供了一个又一个的接口(函数),这样既能给用户提供服务,又能保证操作系统的安全。
★ps:Linux是使用C语言实现的,因此Linux的系统调用本质就是使用C语言实现的函数。
银行的组织结构与操作系统相似。行长借助安保、保洁、技术员等管理了银行里的各项资源;而操作系统借助驱动程序管理计算机上的各项资源(软硬件资源)。为了给用户提供服务,他们都使用了接口式服务,但这种接口式服务对于某些用户来说,仍然使用不便。因而,银行就有了协助老年用户的引导员;而操作系统就有了图形化界面、shell外壳、第三方库来为用户提供便捷的服务。此外,操作系统上,还有各种使用第三方库、系统调用等实现的应用程序(如抖音、淘宝等),为用户提供更加便捷的服务。
操作系统概念
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。它给用户提供了一个稳定、安全、简单的执行环境。
笼统的理解,操作系统包括:①内核(进程管理、内存管理、文件管理、驱动管理)②其他程序(例如:库函数、shell程序等)
在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件
设计操作系统目的
- 与硬件交互,管理所有的软硬件资源
- 为用户程序(应用程序)提供一个良好的执行环境
下图是操作系统在整个计算机体系中起着承上启下的作用。操作系统对下通过驱动程序管理各种硬件;对上为用户提供各种系统接口,对各个软件进行管理。
★ps:计算机管理硬件:①描述起来,用struct结构体 ②组织起来,用链表或其他高效的数据结构
系统调用和库函数概念
在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。
系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。
进程
其实,我们启动一个软件本质就是启动一个进程。在Linux系统上,运行一条命令,如"ls -al",其实就是在系统层面创建了一个进程。因而我们可以得到如下概念↓↓↓
基本概念
●课本概念:程序的一个执行实例,正在执行的程序等。
●内核观点:担当分配系统资源(CPU时间、内存)的实体。
Linux是可以同时加载多个程序的,也就是说,Linux是可以在系统中同时存在大量的进程的。那么,Linux系统就必须对这些进程进行管理。Linux系统是如何管理大量的进程的呢?答案是:先描述,再组织。
对于进程来说,它包含各种属性数据,因此需要一个结构来存储它,即PCB(进程控制块)。
计算机中存在大量的可执行文件,我们双击可执行文件后,本质是将可执行文件从磁盘加载到内存中,该可执行文件中包含了程序的代码和数据。但操作系统中有大量运行的程序,为了管理好这些程序,需要使用PCB结构体将各个运行的程序(进程)的属性数据进行保存。这样操作系统才知道该进程已经运行到哪一行,是否已经执行结束等。
★ps:在操作系统中,会维护一个运行队列run_queue,该队列上链接着等待CPU资源的进程的PCB。当CPU空闲时,则会从run_queue中选择一个进程到CPU中执行,这就是进程调度。
由此,我们可以知道:进程=对应的代码和数据+进程对应的PCB结构体
描述进程-PCB
●进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
●课本上将其称之为PCB,Linux操作系统下的PCB就是task_struct。
在Linux中描述进程的结构体叫做task_struct。task_struct是Linux内核的一种数据结构,它会被装载到内存里并且包含着进程的信息。下表是对task_struct中存储内容的分类↓↓↓
存储项概述 | 具体描述 |
---|---|
标识符 | 描述进程的唯一标识符,用来区别其他进程 |
状态 | 任务状态、退出代码、退出信号等 |
优先级 | 相对于其他进程的优先级 |
程序计数器 | 程序中即将被执行的下一条指令的地址 |
内存指针 | 包括程序代码和进程相关数据的指针,还有和其他程序共享的内存块的指针 |
上下文数据 | 进程执行时处理器的寄存器中的数据 |
I/O状态信息 | 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表 |
记账信息 | 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等 |
其他信息 | —— |
针对于上表中的上下文数据,这里给出一个生活示例进行说明:
大学生参军复学例子
大学里有不少同学会选择参军,如果小明他大二上学期打算参军。此时他可以直接去参军,不和学校内的学生信息管理机构上报吗?如果小明他直接参军,而没有在校报备,等他1年后回来,由于他全科挂科、旷课,被开除了,他就需要从大一重新开始读。
显然,小明去参军是需要和学校报备的,此时学生信息管理机构会将小明的信息存储起来。小明参完军是不是应该跟学校再报备一次,并将学生信息恢复为正常在读状态呢?那是当然。
这里的上下文就等同于小明的在校的信息(上到大二年级,等同于程序执行到第2行代码),像这种离开时将自己的信息保存封存下来,回来后再将信息恢复,这样的操作称为上下文切换(上下文保存及上下文恢复)。当小明回到学校,继续读大二年纪,而不是从大一重新开始读;就等同于程序回到CPU不是从头运行,而是从上次运行停止处继续向下运行。
组织进程
进程结构可以在内核代码中找到它,所有运行在Linux操作系统里的进程都以task_struct链表的形式存储在内核内。
查看进程
进程的信息可以通过/proc
系统文件夹查看。我们通过"ls"命令,可以看到/proc
目录下有许多带数字的文件夹,这些数字就是进程id,用于唯一标识一个进程。
如要获取id为26126的进程信息,我们只需要进入名为26126的目录中查看即可。使用"ls -al"查看目录内的详细内容(这些都是该进程的相关信息),其中,cwd是当前进程的工作目录,exe是当前进程对应的可执行文件的存储位置。如果创建了一个新的进程,则会在/etc目录下创建一个名称与该进程pid相同的目录,目录中保存该进程的相关属性、数据及代码;若终止该进程,则对应的目录会被操作系统自动删除。
还可以使用top命令查看进程的相关信息,其中PID就是进程号(进程id)。
除了上述两种方法,我们还可以使用ps命令配合选项查看进程的相关信息。↓↓↓
示例演示
下面我们编写如下代码,并将它编译运行(可执行文件名为test)。
#include <stdio.h>
#include <unistd.h>int main()
{while(1){sleep(1);}return 0;
}
执行./test程序后,我们再执行ps axj | head - 1 && ps axj | grep test
,可以查看到执行该程序的进程信息↓↓↓
★ps:如果想终止当前在执行的程序,可以使用ctrl+C,或使用kill -9 [进程id]
来结束对应程序。
通过系统调用获取进程标识符
我们可以调用getpid获取当前进程的标识符(进程id),调用getppid获取当前进程的父进程的标识符(父进程id)。在使用该接口时,需要包含sys/types和unistd两个头文件。
下面代码为getpid及getppid的使用示例,运行结果在代码下方↓↓↓
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>int main()
{while(1){printf("my pid is %d\n", getpid());printf("my parent's id is %d\n", getppid());sleep(1);}return 0;
}
我们可以使用ps命令来验证一下上面的pid和ppid是否是当前进程和它的父进程的id↓↓↓
getpid可以获得当前进程的pid,getppid确实可以获得当前进程的父进程。但当前的父进程是哪个程序呢??我们使用ps -p [进程pid]
获取来获取对应pid的进程信息,我们可以发现,该进程的父进程是bash。
为什么父进程是bash呢?bash就是当前与我们进行交互的命令行,为了防止bash执行时该程序崩溃退出,导致整个命令行无法使用。bash会创建子进程,让该子进程执行该程序,即使子进程崩溃退出,也不会影响bash。
通过系统调用创建进程
可以使用fork创建进程。如果创建进程成功,则会给父进程返回子进程id,给子进程返回0;如果创建失败,则会给父进程返回-1。
下面代码演示了如何创建子进程(程序执行结果如代码下方图片所示)↓↓↓
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <unistd.h>int main()
{pid_t id = fork();if(id < 0)//创建子进程失败{perror("fork");exit(1);}else if(id == 0)//子进程执行{printf("I am child process, my pid is %d, my ppid is %d\n", getpid(), getppid());exit(0);}else//父进程执行{printf("I am parent process, my pid is %d\n", getpid());}return 0;
}
父、子进程是代码共享的,但由于fork之后,父子进程获得id值不同,因此子进程执行id == 0
的分支,而父进程执行的是else
分支。
创建子进程本质上,操作系统上就多了一个新的进程,因此操作系统需要给子进程分配一个PCB结构体,并给它一个唯一的p进程id。
★ps:为什么给子进程返回0,给父进程返回子进程的pid?父进程:子进程=1:n,父进程有多个子进程,为了方便子进程管理、标识指定的子进程,需要让fork给父进程返回子进程的pid,当父进程能区分不同的子进程。
🎈欢迎进入从浅学到熟知Linux专栏,查看更多文章。
如果上述内容有任何问题,欢迎在下方留言区指正b( ̄▽ ̄)d
相关文章:

【从浅学到熟知Linux】冯诺依曼体系结构及进程概念详谈!
🏠关于专栏:Linux的浅学到熟知专栏用于记录Linux系统编程、网络编程等内容。 🎯每天努力一点点,技术变化看得见 文章目录 冯诺依曼体系结构操作系统如何理解管理操作系统概念设计操作系统目的系统调用和库函数概念 进程基本概念描…...

word转pdf(前后端最全保姆级别)
word转pdf vue2java 文章目录 word转pdf vue2java一、前端 vue-pdf1、下载依赖2、封装的组件 二、java使用aspose(付费)1.引入库2.封装的工具类3、付费密钥文件 总结 提示:以下是本篇文章正文内容,下面案例可供参考 一、前端 vue…...

深度学习简介
深度学习简介 一、引言:深度学习的兴起 简短介绍深度学习的历史背景 深度学习,作为人工智能领域的一颗冉冉升起的新星,其根源可以追溯到上世纪的感知机学习算法。这种算法模拟人类的神经元行为,是最早期的尝试之一。然而&#x…...
深入探索:使用C++构建顶级性能的网络服务器
在数字化浪潮的推动下,网络服务器作为信息交互的核心枢纽,其性能与稳定性直接决定了互联网应用的服务质量和用户体验。C++,作为一种兼具高效性与灵活性的编程语言,已然成为构建高性能网络服务器的首选工具。本文旨在深入剖析C++在构建顶级性能网络服务器中的关键技术、最佳…...

SpringBoot学习笔记四
SpringBoot学习笔记四-监听机制 1. SpringBoot监听器1.1 无需配置1.1.1 CommandLineRunner使用1.1.2 ApplicationRunner的使用1.1.3 CommandLineRunner与ApplicationRunner的区别 1.2 需要创建META-INF文件,并在其中创建spring.factories,配置相关的信息…...

雄安建博会:中矿雄安新区的总部开工建设
中矿落位雄安:助力国家战略与新区发展 雄安新区,作为中国未来发展的重要战略支点,正迎来一系列央企总部的疏解与建设。最近,中国矿产资源集团有限公司(简称“中矿”)在雄安新区的总部项目正式开工建设&…...

蒙特卡洛方法【强化学习】
强化学习笔记 主要基于b站西湖大学赵世钰老师的【强化学习的数学原理】课程,个人觉得赵老师的课件深入浅出,很适合入门. 第一章 强化学习基本概念 第二章 贝尔曼方程 第三章 贝尔曼最优方程 第四章 值迭代和策略迭代 第五章 强化学习实践—GridWorld 第…...
构建第一个ArkTS之声明式UI描述
ArkTS以声明方式组合和扩展组件来描述应用程序的UI,同时还提供了基本的属性、事件和子组件配置方法,帮助开发者实现应用交互逻辑。 创建组件 根据组件构造方法的不同,创建组件包含有参数和无参数两种方式。 说明 创建组件时不需要new运算…...

pytest教程-25-生成覆盖率报告插件-pytest-cov
领取资料,咨询答疑,请➕wei: June__Go 上一小节我们学习了pytest多重断言插件pytest-assume,本小节我们讲解一下pytest生成覆盖率报告插件pytest-cov。 测量代码覆盖率的工具在测试套件运行时观察你的代码,并跟踪哪些行被运行,…...
特征工程总结
后期总结 Reference [1] 特征工程总结 - 知乎...

JUC并发编程2(高并发,AQS)
JUC AQS核心 当有线程想获取锁时,其中一个线程使用CAS的将state变为1,将加锁线程设为自己。当其他线程来竞争锁时会,判断state是不是0,不是自己就把自己放入阻塞队列种(这个阻塞队列是用双向链表实现)&am…...
Golang 为什么需要用反射
本质上是可以动态获取程序运行时的变量(类型) 比如现在我想实现一个通用的db插入函数,支持我传入所有类型的struct,每一种类型的struct是一个单独的表,以struct的名称作为表名,然后插入到不同的表中。 pa…...

【Linux的进程篇章 - 进程终止和进程等待的理解】
Linux学习笔记---008 Linux之fork函数、进程终止和等待的理解1、fork函数1.1、什么是fork?1.2、fork的功能介绍1.3、fork函数返回值的理解1.4、fork函数的总结 2、进程的终止2.1、终止是在做什么?2.2、进程终止的3种情况 3、进程的终止3.1、进程终止的三种情况3.2、…...
《策略模式(极简c++)》
本文章属于专栏- 概述 - 《设计模式(极简c版)》-CSDN博客 本章简要说明适配器模式。本文分为模式说明、本质思想、实践建议、代码示例四个部分。 模式说明 方案:策略模式是一种行为设计模式,它定义了一系列算法,将每…...
Python向文件里写入数据
直接上代码 name "测试" data name.encode("utf-8")# w特点:文件不存在则创建文件并在打开前清空 f open("db.txt", mode"wb")f.write(data)f.close()可以在 db.txt 文件里看到一句话 测试name "Testing" …...

【网站项目】校园订餐小程序
🙊作者简介:拥有多年开发工作经验,分享技术代码帮助学生学习,独立完成自己的项目或者毕业设计。 代码可以私聊博主获取。🌹赠送计算机毕业设计600个选题excel文件,帮助大学选题。赠送开题报告模板ÿ…...
vue-指令v-for
<!DOCTYPE html> <html lang"en"> <head> <meta charset"UTF-8"> <meta name"viewport" content"widthdevice-width, initial-scale1.0"> <title>vue-指令v-for</title> </head> …...

Python项目1 外星人入侵_外星人
在本章中,我们将在游戏《外星人入侵》中添加外星人。首先,我们在屏幕上边缘附近添加一个外星人,然后生成一群外星人。我们让这群外星人向两边和下面移 动,并删除被子弹击中的外星人。最后,我们将显示玩家拥有的飞船数量…...

导入项目运行后,报错java: Cannot find JDK ‘XX‘ for module ‘XX‘
解决方案: 1、删除.idea和.iml文件 2、右击此module,点击 Open Module Settings 在 Module SDK 中选择所安装的java版本后,点击右下角 Apply,会再生成.idea文件; 那.iml文件呢?操作步骤: 按两下…...
JS rgb,hex颜色值转换
颜色值转化 rgb颜色值转换为hex颜色值(rgb>hex) hex颜色值转换为rgb颜色值(hex>rgb) 代码: const hex2Rgb (hex) > {return rgb(${parseInt(hex.slice(1, 3), 16)},${parseInt(hex.slice(3, 5), 16)},${p…...
[2025CVPR]DeepVideo-R1:基于难度感知回归GRPO的视频强化微调框架详解
突破视频大语言模型推理瓶颈,在多个视频基准上实现SOTA性能 一、核心问题与创新亮点 1.1 GRPO在视频任务中的两大挑战 安全措施依赖问题 GRPO使用min和clip函数限制策略更新幅度,导致: 梯度抑制:当新旧策略差异过大时梯度消失收敛困难:策略无法充分优化# 传统GRPO的梯…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...

Prompt Tuning、P-Tuning、Prefix Tuning的区别
一、Prompt Tuning、P-Tuning、Prefix Tuning的区别 1. Prompt Tuning(提示调优) 核心思想:固定预训练模型参数,仅学习额外的连续提示向量(通常是嵌入层的一部分)。实现方式:在输入文本前添加可训练的连续向量(软提示),模型只更新这些提示参数。优势:参数量少(仅提…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
Spring Boot 实现流式响应(兼容 2.7.x)
在实际开发中,我们可能会遇到一些流式数据处理的场景,比如接收来自上游接口的 Server-Sent Events(SSE) 或 流式 JSON 内容,并将其原样中转给前端页面或客户端。这种情况下,传统的 RestTemplate 缓存机制会…...

Cinnamon修改面板小工具图标
Cinnamon开始菜单-CSDN博客 设置模块都是做好的,比GNOME简单得多! 在 applet.js 里增加 const Settings imports.ui.settings;this.settings new Settings.AppletSettings(this, HTYMenusonichy, instance_id); this.settings.bind(menu-icon, menu…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...

AI,如何重构理解、匹配与决策?
AI 时代,我们如何理解消费? 作者|王彬 封面|Unplash 人们通过信息理解世界。 曾几何时,PC 与移动互联网重塑了人们的购物路径:信息变得唾手可得,商品决策变得高度依赖内容。 但 AI 时代的来…...

【Linux】自动化构建-Make/Makefile
前言 上文我们讲到了Linux中的编译器gcc/g 【Linux】编译器gcc/g及其库的详细介绍-CSDN博客 本来我们将一个对于编译来说很重要的工具:make/makfile 1.背景 在一个工程中源文件不计其数,其按类型、功能、模块分别放在若干个目录中,mak…...
2.2.2 ASPICE的需求分析
ASPICE的需求分析是汽车软件开发过程中至关重要的一环,它涉及到对需求进行详细分析、验证和确认,以确保软件产品能够满足客户和用户的需求。在ASPICE中,需求分析的关键步骤包括: 需求细化:将从需求收集阶段获得的高层需…...