冯诺依曼体系结构
我们常见的计算机,如笔记本。我们不常见的计算机,如服务器,大部分都遵守冯诺依曼体系.
截至目前,我们所认识的计算机,都是有一个个的硬件组件组成。
- 输入单元:包括键盘, 鼠标,扫描仪, 写板等
- 中央处理器(CPU):含有运算器和控制器等
- 输出单元:显示器,打印机等
关于冯诺依曼,必须强调几点:
- 这里的存储器指的是内存
- 不考虑缓存情况,这里的CPU能且只能对内存进行读写,不能访问外设(输入或输出设备)--------数据层面
- 外设(输入或输出设备)要输入或者输出数据,也只能写入内存或者从内存中读取。--------数据层面
- 一句话,所有设备都只能直接和内存打交道。--------数据层面
为什么外设不与CPU直接交互?
因为CPU(中央处理器)的运算速度是非常快的,而外设的速度有比CPU的速度慢了很多,在这之前我们知道一个木桶原理,桶中的水的多少,不是取决于桶中最长木板的长度,而是取决桶中最短木板的长度。所以在外设与CPU之间加了存储器作为中介,平衡外设与CPU之间差距。
对冯诺依曼的理解,不能停留在概念上,要深入到对软件数据流理解上,如果我们在登录上qq和某位朋友聊天开始,数据的流动过程(不考虑网络)
数据流动时必须先从外设到内存
操作系统
任何计算机系统都包含一个基本的程序集合,称为操作系统(OS)。笼统的理解,操作系统包括:
- 内核(进程管理,内存管理,文件管理,驱动管理)
- 其他程序(例如函数库,shell程序等等)
设计OS的目的
- 与硬件交互,管理所有的软硬件资源
- 为用户程序(应用程序)提供一个良好的执行环境
定位
在整个计算机软硬件架构中,操作系统的定位是:一款纯正的“搞管理”的软件
如何理解 “管理”
管理的本质:先描述,在组织
整个计算机的软硬件结构是层状的结构
我们在使用时,一般不能绕过特定层,而必须是从上到下去贯穿,自低向上去获取。
总结
计算机管理硬件
- 描述起来,用struct结构体
- 组织起来,用链表或其他高效的数据结构
系统调用和库函数概念
- 在开发角度,操作系统对外会表现为一个整体,但是会暴露自己的部分接口,供上层开发使用,这部分由操作系统提供的接口,叫做系统调用。
- 系统调用在使用上,功能比较基础,对用户的要求相对也比较高,所以,有心的开发者可以对部分系统调用进行适度封装,从而形成库,有了库,就很有利于更上层用户或者开发者进行二次开发。
承上启下
那在还没有学习进程之前,就问大家,操作系统是怎么管理进行进程管理的呢?很简单,先把进程描述起来,再把进程组织起来!
进程
我们以前的任何启动并运行程序的行为------由操作系统帮助我们将程序转换成为进程-----完成特定的任务!
进程的属性与文件的属性有关系?
PUB中的属性是有操作系统重新构建,跟文件的属性是不一样的,有关系但关系不大
什么是进程?
进程 = 内核关于进程的相关数据结构 + 当前进程的代码和数据
描述进程-PCB
- 进程信息被放在一个叫做进程控制块的数据结构中,可以理解为进程属性的集合。
- 课本上称之为PCB(process control block),Linux操作系统下的PCB是: task_struct
task_struct
是双向循环链表
为什么进程中需要PCB?
因为是为了更好的描述进程。
task_struct-PCB的一种
- 在Linux中描述进程的结构体叫做task_struct。
- task_struct是Linux内核的一种数据结构,它会被装载到RAM(内存)里并且包含着进程的信息。
task_ struct内容分类
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
组织进程
可以在内核源代码里找到它。所有运行在系统里的进程都以task_struct链表的形式存在内核里。
查看进程
进程的原码和数据
ps axj | head -1 && ps ajx | grep 进程名称
:查看我进程的相关属性
ps axj
:查看系统中所有进程
grep 进程名称
:要看的进程
head -1
:将罗列出的行,只显示出前1行
&&
:前面的指令执行完,接着执行后面的指令。
这样的两个进程,./test.txt
是我们写的进程,grep
是查看进程的进程
ps axj | head -1 && ps ajx | grep test.txt | grep -v grep
过滤调grep
grep -v 进程名称
过滤调的进程
查看父进程和子进程的PID
getpid()
获取当前进程的PID
getppid()
获取当前进程的父进程PID
进程的信息可以通过 /proc
系统文件夹查看
proc
保存操作系统中进程和进程相关属性的目录,proc
目录是内存级的目录,只有在操作系统启动时才会存在。
当操作系统有一个进程,操作系统自动就会/proc
目录下创造一个以PID号命名的目录文件。
当杀死这个进程之后,操作系统会删除掉在/proc
中为PID命名的文件。因此/proc
文件是动态变化的。
查看子进程的父进程的是什么
kill -9 PID
:这条指令也可以杀死进程。
- bash命令行解释器,本质上它也是一个进程!
- 命令行启动的所有的程序,最终都会变成进程,而该进程对应的父进程都是bash。
- 我们自己命令所起动的程序都是
back
的子进程,有特殊情况
任何进程运行起来都有它对应的PID,操作系统在创建PCB的时候,就会自动申请对应的PTD。
通过系统调用创建进程-fork认识
man fork
这条条指令查看fork
的手册
fork()
功能: 创建子进程
返回值: 有两个返回值,给父进程返回子进程的PID,子进程返回0,创建子进程失败返回-1
如何创建子进程?
- fork之后,执行流会变成2个执行流
- fork之后,谁先运行由调度器决定
- fork之后, fork之后的代码共享,通常我们通过
if
和else if
来进行执行流分流!
进程在运行的时候,具有独立性!父子进程运行的时候也是一样的,父进程不受影响
fork如何看待-----代码和数据
如何理解fork的两返回值
当代码执行到fork
之后代码共享,产生了子进程。父进程执行到return 0
后,fork
之后代码,子进程又执行到return 0
,所以产生了两返回值。 fork之后,父子进程谁先运行由调度器决定。
理解子进程为什么从fork函数调用之后开始执行
对于原因也很合逻辑,如果子进程也从main开头到尾执行所有指令,那它执行到fork指令时也必定会创建一个子子程,如此下去这个小小的程序就可以创建无数多个进程可以把你的电脑搞瘫痪,