目录
2.3.2、进程状态:就绪/运行/阻塞(从cpu的角度理解)
1、操作系统的描述
1.1、操作系统是什么?
操作系统 = 操作系统内核 + 一堆应用
1.2、操作系统在做什么?
操作系统在管理计算机的软硬件资源。
1.3、操作系统使怎样完成这些事的?
通过管理完成的。
管理 = 描述(结构体) + 组织(串联结构体)
1.4、系统调用 & 库函数
系统调用函数:错做系统内核提供的函数
库函数:c标准库提供的函数。库函数的代码实现中调用了系统调用函数。
2、进程相关概念
2.1 程序 & 进程
程序:源代码经过编译产生的可执行文件,是静态的
进程:程序运行起来的实例,是动态的
2.2 管理进程
管理 = 描述(PCB) + 组织(链表)
2.3 描述(PCB)
2.3.1、进程号(PID)
1 #include<stdio.h>
2 #include<unistd.h>
3 int main(){
4 while(1){
5 printf("pid = %d\n",getpid());
6 sleep(3);
7 }
8 return 0;
9 }
10
2.3.2、进程状态:就绪/运行/阻塞(从cpu的角度理解)
运行:进程占用cpu,并在cpu上运行(进程正在使用cpu来执行自己的代码)。
就绪:进程已具备了运行条件,但是cpu还没有分配过来;理解为进程已经将运行前的准备工作全部做好了,就等着系统调用,占用cpu。
阻塞:进程因等待某件事而暂时不能运行(例:iO输入、调用某些阻塞接口)。
2.3.3、并发&并行
并发:多个进程在一个cpu下,采用进程切换的方式,各自独占cpu运行各自的代码,交替运行,让多个进程都得以推进。
并行:多个进程在多个cpu下,同时运行各自的代码。
2.3.4:细分的进程状态(重点)
R 运行状态:可能是在执行代码,也有可能是在运行队列(就绪队列)。也就是在就绪队列 + 运行状态的进程。
S 可中断睡眠状态:进程正在睡眠(被阻塞),等待资源到来时唤醒,也可以通过其他进程信号或时钟中断唤醒,进入运行队列。
D 不可中断睡眠状态(磁盘休眠状态):通常是等待某一个IO的结束。
T 暂停状态(ctrl + z):不要用ctrl + z来结束进程,不是结束,而是暂停。终止一个进程为ctrl + c.
t 跟踪状态:调试程序的时候可以看见。
X 死亡状态:这个状态是用户看不到的,在PCB被内核释放的时候,进程会被置为X,紧接着进程就退出了。
Z 僵尸状态:子进程先于父进程退出,子进程就变成了僵尸进程。
此外,有+和无+的区别:
有+:表示进程是一个前台进程。特性为:阻塞bash,让bash无法处理其他问题。
没有+:表示进程是一个后台进程。特性:不会阻塞启动的bash,默默的在后台运行。
2.3.5、程序计数器
进程切换:进程从cpu当中剥离出来,将cpu资源让其他程序使用。在进程切换的时候要保存现场(记录进程目前执行到哪里&即将执行什么指令)。恢复现场:通过程序计数器的内容来确定下一步要执行的指令。指令指的是汇编指令,而不是原生的高级语言的代码。
程序计数器的作用:记录当前进程下一步要执行的指令。本质就是为下一次执行做准备。
2.3.6、上下文信息
作用:保存寄存器当中的信息。
寄存器是OS的资源,在进程切换的过程中如果不保存寄存器的信息,等到该进程再次被cpu调用的时候,可能会由于寄存器的内容被其他进程改变而导致程序运行错误。
2.3.6、内存指针
指向”程序地址空间“,这里的程序地址空间本质上是OS虚拟出来的虚拟地址空间。
2.3.7、记账信息
记录使用cpu的时长、占用内存大小。
2.3.7、IO信息
保存进程打开的文件信息
每一个进程被创建的时候都会默认打开三个文件:
stdin:标准输入 :scanf
stdout:标准输出 :printf
stderr:标准错误 :perror
验证:
①创建一个进程
②在/proc目录下找到并进入以进程号命名的目录
③进入fd目录,就是那三个文件。
2.4、创建子进程
1、fork函数
2、函数返回值
①创建成功:
fork会返回两次,在父进程中返回一次,在子进程中返回一次。
返回值 > 0 :返回给父进程
返回值 == 0:返回给子进程
②创建失败:返回 -1
3、子进程的作用
父进程想把”脏活累活“(可能导致程序崩溃)都交给子进程去处理。
2.5僵尸进程 &僵尸状态
概念:子进程先于父进程退出,子进程就会变为僵尸进程。
形成原因:
子进程在退出的时候会告知父进程(信号),父进程忽略处理,父进程并没有回收子进程的状态信息。
此时,子进程就会变为僵尸状态(Z状态)。
危害:
子进程的PCB没有被释放,会造成内存泄露。
解决方案:
①杀死父进程,子进程由僵尸进程转变为孤儿进程(不推荐)
②重启操作系统(不推荐)
③父进程进行进程等待
扩展内容
kill命令可以终止一个进程
2.6、孤儿进程
概念:
形成原因:
父进程先于子进程退出后,既定回收子进程的父进程就不在了,子进程就变成了孤儿进程。此时它会被1号进程所领养。
1号进程:/user/lib/systemd/:操作系统启动的第一个进程,后续有很多进程都是由该进程创建出来的或者由该进程的子孙进程创建出来的操作系统初始化的一些工作。
2.7、环境变量
1、概念:
环境变量指在操作系统中用来指定操作系统运行的一些参数。也就是说,操作系统通过环境变量来找到运行时的一些资源。执行命令的时候,帮助用户找到该命令在哪一个位置。
例如:链接的时候,帮助链接器找到动态库(标准库的)。(用户自己编写的动态库,需要自己指定环境变量)
2、常见的环境变量
①PATH:指定可执行程序的搜索路径。程序员执行的命令之所以能够被找到,就是环境变量的作用。
②HOME:登录到Linux操作系统的家目录
HOME = /home/DL
③SHELL:当前的命令行解释器,默认是”/bin/bash“
3、查看当前环境变量
①env命令
②echo $[环境变量名称]
系统当中的环境变量是有多个的,每一个环境变量的组织方式都是 :
环境变量名称 = vaule(环境变量的值,多个值之间用:隔开)
4、环境变量对应的文件
① 系统级文件:/etc/bashrc
针对与各个用户都起作用(root用户才有权限修改),强烈不推荐修改系统级的文件,因为会影响其他用户。
②用户级文件:~/.bashrc && ~/.bash_profile
~/.bash_profile包含~/.bashrc包含/etc/bashr,推荐修改,因为这两个文件只会对自己用户的环境变量做出修改,指挥影响自己。
5、修改环境变量
命名范式:
①命令行当中直接修改:
特点:临时生效,在当前终端内生效,如果重新打开终端,是找不到该环境变量的。
新增环境变量:命名范式可以不要$环境变量名称:
修改老的环境变量:必须加上 $环境变量名称,如果不加之前的环境变量的值就丢失了。
②文件中修改:
特点:修改后不会立即生效。需要配合source[环境变量的名称]激活。永久生效的。
新增环境变量:在文件末尾直接添加:export 环境变量 = 【新添加的环境变量内容】
修改老的环境变量:在老的后面添加”:【新添加的环境变量内容】“
6、环境变量的组织方式
通过字符指针数组的方式组织,数组最后的元素以NULL结尾(当程序拿到环境变量的时候,读取到NULL,说明已经读取完毕)
7、代码获取环境变量
①通过main函数的参数获取,main函数的三个参数的含义:
②environ
③getenv
2.8、进程虚拟地址空间
1、 虚拟地址
我们在c/c++语言所看到的地址,全部都是虚拟地址。物理地址一般·用户看不到,由操作系统统一管理,操作系统负责将程序当中的虚拟地址转换为物理地址。
2、进程虚拟地址空间
3、页表
映射关系:
答: 虚拟地址空间分为一页一页,物理内存分为一块一块,使用页表将页和块映射起来。
为什么内存分配的时候是一页一页离散的分配的方式?
答:防止内存碎片。
fork在创建子进程的时候,会不会拷贝页表?
答:会,因为每个进程都有自己的页表,子进程最初的页表映射的内容就是来自父进程。后面子进程在运行的时候可能会有不同的映射关系。
2.9、进程优先级
cpu资源分配的先后顺序就是指进程的优先权。
ps -l 命令显示的内容:
PRI :表示进程可被执行的优先级,值越小,优先级越高。
NI :进程的nice值(表示进程可被执行的优先级的修正值)