目录
操作系统是什么
进程
进程的状态
1.并行和并发
2.时间片
进程优先级
进程切换
task_struct内容分类:
操作系统是什么
操作系统本质上是一款纯正的“搞管理”的软件
你的程序不能直接写入硬件,都必须通过操作系统
对软硬件之间进行交互:对上要给用户提供一个稳定的,高效的,安全的运行环境(目的!)
以人为本! 对下软硬件资源的管理,稳定的,高效的,安全的,能进行良好的工作(手段)
操作系统是怎么管理的:通过数据结构task_struct(PCB),对数据结构的增删查改来进行对数据的管理也就是:先描述在组织!!
操作系统对上怎么操作的?由于操作系统不允许用户直接访问所以开放接口:使用系统调用的接口
操作系统必须向上提供各种接口,方便上层使用—开放(只开放)
因为操作系统的底层是C语言写的,所以接口只能是C语言的接口,所有软件的底层,都必须和c直接或间接相关。Java的虚拟机,和python的解释都是用c写的
然而系统调用接口对于大部分学习成本高所以开放用户操作接口,比如程序员给写好的库,或者shell外壳,或者直接操作的图形化界面
系统调用接口,需要对系统有所了解,对一般程序员,使用会比较麻烦:库
进程
进程 = 内核数据结构(task_struct)+ 程序的代码和数据
运行起来的程序—》进程会被根据task_struct属性被os调度器调度,运行
课本:内核观点:担当分配系统资源(CPU时间,内存)的实体—正确但不好理解
一个程序从磁盘中读取到内存,它还不是个进程,要在操作系统存在在的数据结构中才叫进程。就比如我在清华大学,我就是清华大学的学生了吗?不是,要在清华大学的学生系统里才算。
也就是学生 = 人+属性;
进程 = 数据加属性。
操作系统中存在数据结构task_struct。我们的程序代码只是作为一个结构体的属性,由一个指针指向即可,结构体中还存在其它属性:编号,状态等等。实际上操作系统结构体里的属性相当多
Task——struct中重要的属性
把程序运行起来,本质就是在系统中启动了一个进程
PID进程标识符 区分进程唯一性
Exe属性 是可执行程序的位置,在磁盘中的位置磁盘
cwd(当前目录)
当前路径:进程的CWD
Proc是内存级的属性文件,关机即清空,内存中的数据以文件的形式存在
Ppid父进程
Bash 命令行解释器 –shell所有命令行解释器的总称
命令行中,执行命令/执行程序,本质是bash的进程,创建的子进程了,由子进程执行我们的代码。 使用系统调用,创建进程
Fork创建一个子进程,返回一个
Linux进程整体是树形结构
父子进程 fork的代码共享,数据各自私有一份
进程之间有很强的独立性,多个进程之间,运行时互不影响,即便是父子
代码是只读的
一个函数,fork,怎么会有俩返回值
创建子进程的task_struct是拷贝父进程的
在fork返回之前,都已经生成父子进程了,只是还没有返回,所以都有return 语句,所以有俩返回值、。
Fork之后,谁先运行不确定。由OS调度器自主决定
PCB :task_struck-PCB的一种
进程的状态
等键盘的叫阻塞
等cpu的叫运行
1.并行和并发
CPU执行进程代码,不是把进程代码执行完毕,才开始执行下一个。而是给每一个进程预分配一个 时间片,基于时间片,进行调度轮转(单CPU下),并发
并发:在一段时间之内,让多个进程都得以推进,称之为井发
并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行
2.时间片
Linux/windows民用级别的操作系统,(分时操作系统) ->调度任务追求公平
3.进程具有独立性
- 代码共享,数据私有:父子进程通过
fork
创建,代码共享,数据各自私有一份。进程之间有很强的独立性,多个进程之间运行时互不影响,即便是父子进程。 - 返回值与调度:一个函数
fork
会有两个返回值。在fork
返回之前,已经生成了父子进程,只是还没有返回,所以都有return
语句。fork
之后,谁先运行不确定,由操作系统调度器自主决定。
实时操作系统
等待的本质 :连入目标外部设备,CPU不调度!
阻塞挂起状态,在内存严重不足的时候,代码和数据会换入到磁盘的swap分区,只有,取到数据进入运行队列的时候将数据换入,效率慢了,时间换空间 。云服务器不用swap分区,换入换出是io很慢*
等待磁盘是状态D键盘S
Main 的返回值是告知父进程/操作系统,我把任务完成的怎么样
僵尸状态--Z:维持退出信息,方便父进程和操作系统来进行查询,在查询结束后进程才会死亡
先创建task_struck再导入数据,task_struck创建好的时候就已经是个进程了。
释放的时候先释放代码和数据。
僵尸进程,如果没人管我,我会一直僵尸
父进程退出,子进程会被系统领养,叫孤儿进程
//
static const char * const task_state_array[] = {"R (running)", /* 0 运行状态*/ "S (sleeping)", /* 1 休眠状态 */"D (disk sleep)", /* 2 磁盘级的休眠状态--不可打断*/"T (stopped)", /* 4 进程做了非法但是不致命的操作,被OS暂停了*/"t (tracing stop)", /*8 进程被追踪的时候,断点停下,状态就是t*/"X (dead)", /* 16 死亡状态*/"Z (zombie)", /* 32 僵尸状态*/
}
先创建task_struck再导入数据,task_struck创建好的时候就已经是个进程了。
释放的时候先释放代码和数据。
僵尸进程,如果没人管我,我会一直僵尸
父进程退出,子进程会被系统领养,叫孤儿进程
ps命令加pid可以查看进程状态
这个图片在杀死子进程的时候状态变成了Z
进程优先级
优先级数字越小优先级越高
PRI:当前进度的优先级
NI:优先级的nice数据 优先级的修正数据 -20~19
最终优先级 = pri(默认/老的default 80 )+nice
进程切换
Eip(pc)寄存器,当前正在执行指令的下一条的地址 pc=当前地址+读进来的指令长度,ir读进来后pc指针就可以更新
Ir指令寄存器 正在执行的指令
切换核心:进程上下文数据的保存和恢复
1、取指令2、更新pc 3、分析执行指令
Cpu处理数据的时候产生的数据叫上下文数据
进程上下文数据保存在PCB‘里就好了
调度
FIDO调度 几乎没用了 因为有优先级
linux真实调度算法
新进程和时间片到了的进程被放到过期队列,不能放到活跃队列(会导致进程饥饿问题)
Active队列结束完了后,交换过期队列和活跃队列的指针就可以了
Nr_active 是队列有几个进程
Bit_map [5]位图,一次跳32个位置,最多查37次,
Linux内核O(1)调度算法
通过一个变量找结构体
task_struct内容分类:
标识符
描述本进程的唯一标示符,用来区别其他进程。
这是进程的一个唯一标识,用于在系统中区分不同的进程。
状态
任务状态,退出代码,退出信号等。
进程的状态包括运行、睡眠、停止等,以及进程退出时的相关代码和信号。
优先级
相对于其他进程的优先级。
进程的优先级决定了它在系统中的执行顺序,优先级高的进程会先得到 CPU 资源。
程序计数器
程序中即将被执行的下一条指令的地址。
这是 CPU 在执行程序时用于记录下一条要执行指令的地址的寄存器。
内存指针
包括程序代码和进程相关数据的指针,还有和其他进程共享的内存块的指针。
进程在内存中的位置和数据存储的指针,包括与其他进程共享的内存。
上下文数据
进程执行时处理器的寄存器中的数据(例如,要加 CPU,寄存器)。
当进程被切换时,当前的寄存器状态需要保存,这就是上下文数据。
I/O 状态信息
包括显示的 I/O 请求,分配给进程的 I/O 设备和被进程使用的文件列表。
进程在进行 I/O 操作时的相关状态和设备使用情况。
记账信息
可能包括处理器时间总和,使用的时钟数总和,时间限制,记账号等。
用于记录进程使用系统资源的情况,如 CPU 时间、时钟周期等。