目录
1.冯诺依曼体系结构
独立:
CPU:运算器和控制器
输入设备:话筒,摄像头,键盘,鼠标,磁盘,网卡等。
输出设备:声卡,显卡,网卡,磁盘,显示器,打印机等。
存储器指的是内存---掉电易失
设备是总线连接的----主板
设备中数据的流动,本质是设备之间会进行数据的来回拷贝,拷贝的整体速度,是决定计算机效率的重要指标。
距离CPU距离越近的存储单元,效率越高,造价高,单体容量越小。
距离CPU越远的存储单元,效率越低,造价便宜,单体容量大。
内存看做一个非常大的缓存介于设备和CPU之间,计算机的效率最重就变成了内存效率为主。引入内存把效率问题转化为了软件问题。
场景1:程序在运行的时候,必须把程序先加载到内存,在数据层面,CPU只和内存打交道,外设只和内存打交道。
2.操作系统
任何计算机系统都包含一个基本的程序集合,称为操作系统(os),第一个被加载的软件是操作系统,操作系统是一个进行软硬件资源管理的软件。操作系统包括:
1.内核(进程管理,内存管理,文件管理,驱动管理)
2.其他程序(函数库,shell程序等)
设计操作系统的目的:
1.与硬件交互,管理所有的软硬件资源
2.为用户程序提供一个良好的执行环境
计算机管理硬件:
1.描述起来,结构体
2.组织起来,高效的数据结构
系统调用:操作系统对外表现一个整体,暴露自己的部分接口,这个接口就叫做系统调用。
库函数:对部分系统调用进行适度封装,形成了库。
3.进程
事实:
- 我们可以同时启动多个程序----我们一定要将多个.exe加载到内存。
- 操作系统要管理多个加载到内存的程序。
- 操作系统通过先描述再组织管理加载到内存的程序。
1.基本概念
课本概念:程序的一个执行实例,正在执行的程序等。
内核观点:担当分配系统资源(CPU时间,内存)的实体。
2.描述进程-PCB
进程信息放在一个叫做进程控制块的数据结构中,为进程属性的集合。
Linux下的PCB是:task struct
进程=内核数据结构+可执行程序
组织:所有运行在系统里的进程都以task_struct链表的形式存在内核里
所有对进程的控制和操作,都只和进程的PCB有关,和进程的可执行程序没有关系。
task_struct中的内容:
- 标示符: 描述本进程的唯一标示符,用来区别其他进程。
- 状态: 任务状态,退出代码,退出信号等。
- 优先级: 相对于其他进程的优先级。
- 程序计数器: 程序中即将被执行的下一条指令的地址。
- 内存指针: 包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针
- 上下文数据: 进程执行时处理器的寄存器中的数据[休学例子,要加图CPU,寄存器]。
- I/O状态信息: 包括显示的I/O请求,分配给进程的I/O设备和被进程使用的文件列表。
- 记账信息: 可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
- 其他信息
创建一个这样的程序,即可查看到该进程
3.系统调用查看pid
![](https://img-blog.csdnimg.cn/direct/3000fc0460ad426f9010f3c574b3f3be.png)
![](https://img-blog.csdnimg.cn/direct/db3388a83ef148daa8698cb7bfa1c8d0.png)
![](https://img-blog.csdnimg.cn/direct/2922d0a3a7c646f199bc9f95a47f3f6d.png)
4.系统调用创建进程-fork初识
fork之后,代码共享,fork之后形成分支,一个为原进程(父进程),一个为它的子进程,父子进程代码共享,数据各自开辟空间,私有一份(写时拷贝),fork有两个返回值,如果成功将子进程的pid返回给父进程,将0返回给子进程。一般而言,我们想让父子做不同的事情。
子进程被创建,是以父进程为模板的。一个进程崩溃了,不会影响其他进程,进程之间是具有独立性的,互相不能影响。可以用同一个变量名,表示不同的内存。
4.进程状态
进程排队一定是在等待某种资源,进程不是一直在运行的,可能在等待某种软硬件资源,进程放在了CPU上,也不是一直会运行的,只要是排队,一定是进程的task_struct进行排队,一个task_struct可以被连入多种数据结构中。
所谓的状态,本质就是一个整形变量,在task_struct中的一个整形变量,状态决定了你的后续动作,Linux中可能会存在多个进程都要根据它的状态执行后续动作,一个CPU一个运行队列。
1.阻塞:
当我们的进程在进行等待软硬件资源的时候,资源如果没有就绪,我们的进程task_struct只能1.将自己设置为阻塞状态。2.将自己的PCB连入等待的资源提供的等待队列。状态的变迁,引起的是PCB会被OS变迁到不同的队列中。
2.挂起:
前提:计算机资源已经比较吃紧了!在操作系统中,挂起是指将一个进程或线程的执行暂时中止,并将其保存到外部存储器(如硬盘)中,以便稍后重新恢复执行。挂起通常是由操作系统或者其他进程发起的,目的是暂时释放进程或线程占用的系统资源,或者让其他优先级更高的任务先执行。
- R运行状态(running): 并不意味着进程一定在运行中,它表明进程要么是在运行中要么在运行队列里。
- S睡眠状态(sleeping): 意味着进程在等待事件完成(这里的睡眠有时候也叫做可中断睡眠 (interruptible sleep))。
- D磁盘休眠状态(Disk sleep)有时候也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束。
- T停止状态(stopped): 可以通过发送 SIGSTOP 信号给进程来停止(T)进程。这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行。
- X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态。
3.Z-僵尸进程
僵尸进程危害:
- 进程的退出状态必须被维持下去,因为他要告诉关心它的进程(父进程),你交给我的任务,我办的怎么样了。父进程如果一直不读取,那子进程就一直处于Z状态。
- 维护退出状态本身就是要用数据维护,也属于进程基本信息,所以保存在task_struct(PCB)中,话 说,Z状态一直不退出,PCB一直都要维护。
- 那一个父进程创建了很多子进程,就是不回收,是不是就会造成内存资源的浪费?是的!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量(对象),是要在内存的某个位置进行开辟空间!
- 内存泄漏。
4.孤儿进程
父进程先退出,子进程就称之为孤儿进程,该进程转到后台,该子进程被1号进程领养,由1号进程回收。
5.进程优先级
- cpu资源分配的先后顺序,就是指进程的优先权(priority)。
- 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
- 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
每个进程都有一些信息:
- UID : 代表执行者的身份
- PID : 代表这个进程的代号
- PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
- PRI :代表这个进程可被执行的优先级,其值越小越早被执行(默认是80)
- NI :代表这个进程的nice值
PRI就是程序被CPU执行的先后顺序,此值越小进程的优先级越高,而NI表示进程可被执行的优先级的修正数值,会影响到进程的优先级变化。PRI(new)=PRI(old)+nice,当nice值为负值时,该程序将会优先级值变小,优先级变高,调整进程优先级就是调整nice值,nice取值范围是-20到19.
top命令可更改nice,进入top后按“r”–>输入进程PID–>输入nice值。
Linux内核进程调度队列
一个CPU拥有一个runqueue,如果有多个CPU就要考虑进程个数的负载均衡问题,
活动队列
- 时间片还没有结束的所有进程都按照优先级放在该队列
- nr_active: 总共有多少个运行状态的进程
- queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级!
- 从该结构中,选择一个最合适的进程,过程是怎么的呢?
1. 从0下表开始遍历queue[140]2. 找到第一个非空队列,该队列必定为优先级最高的队列3. 拿到选中队列的第一个进程,开始运行,调度完成!4. 遍历queue[140]时间复杂度是常数!但还是太低效了!
- bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用5*32个比特位表示队列是否为空,这样,便可以大大提高查找效率
过期队列
- 过期队列和活动队列结构一模一样
- 过期队列上放置的进程,都是时间片耗尽的进程
- 当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算
active指针和expired指针
- active指针永远指向活动队列
- expired指针永远指向过期队列
- 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的。
- 没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程
在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法