目录
内容接上文:
1.进程状态
状态有很多:运行,新建,就绪,挂起等...
描述:进程状态仅仅是对于某个进程的某个阶段的描述,但是描述是需要操作系统依托的。操作系统的操作系统描述是整体的范式,而Linux的状态则是具体的操作系统的描述。
目的:进程那么多状态本质是服务于用户的体验。
1.只针对操作系统的宏观概念
首先,每一个进程都会被操作系统描述成PBC,并且存放在内存中被操作系统加以管控。至于怎么管控,操作系统会把PBC链接成一串,再生成所谓的运行队列将一串PBC加以管控。CPU是有限的,但是进程是有很多的,所以需要操作系统通过对该生成的运行队列进行执行,队列先来后到的运行,这便是运行排队。
那么CPU不能等到一个进程完全结束才进行下一个,这样的操作限制性非常高,CPU很快,所以每个进程被“切片”成一小段进程片,每个片段运行结束进行下一个进程。其中就有了不同的状态描述进程。状态是需要被操作系统识别的,所以它也是一种属性;既然是属性,那么一定要被存储的,它被存储在对应进程的PCB中,而这串被描述的属性其实就是一个整型类型的东西用来代表进程的状态属性。
1.CPU很少但是很快,进程有很多,那么将进程的PCB入运行队列中,让PCB等待或正在被CPU处理——运行状态(R)
2.进程执行需要对硬件进行使用,但是硬件是有限的,PCB加载硬件也需要队列运行。那么当我们将PCB从CPU中加载到外设中,进行运行排列,等待或正在被硬件处理——阻塞状态
此外;其实操作系统还需要知道硬件的状态,当硬件执行了对于进程,进程会被重新变为运行状态并且排会CPU的运行队列之中。
3.多个PCB在硬件中为阻塞状态时,要知道硬件的内存是有限的,PCB占内存,好多PCB短期之内不能被读取,万一硬件的内存不够PCB存储;此时操作系统把短期不用的进程对用的代码暂时保存到磁盘中,等有空间再放回内存中,以达到节省空间(操作系统代码加载回磁盘和传回内存叫对内存数据的唤入唤出)——挂起状态
2.Linux的进程状态
Linux源代码中有记录对应的进程状态
系统当中有很多信号针对进程。
1.运行状态(R)
对一个纯死循环的进程进行查看进程,会发现STAT处在R状态
2.休眠状态(S)
对循环中加入打印函数查看进程,会发现STAT处在S状态——一旦访问外设,外设加载执行比CPU慢,所以一般都是在休眠等待(是一种阻塞状态)
3.暂停状态/浅度睡眠状态(T)
对正在运行的进程通过指令:kill -19 pid;使得该进程暂停
此时我们发现进程暂停了(暂停状态是阻塞状态的一种,挂起状态不需要被用户知道,所以没有直接显示)
kill -18 pid指令可以使得暂停的进程重新运行
只是此时的进程少了加号修饰,并且不在前台显现,想杀掉进程必须kill -9 pid。 所以我们能知道状态带加号是指该进程前台加载,无加号指该进程后台加载。后台加载表现为,代码运行结果会打到面板上,我们也可以写指令,但是我们不能CTRL+C干掉进程。
4.深度睡眠状态(D)
对阻塞的进程不能转化为挂起状态。不能被操作系统杀掉阻塞状态的代码变为挂起状态,只能通过断电,或者进程自己醒来。(是一种阻塞状态)
5.当前进程正在被追踪(t)
也是一种暂停的状态
6.死亡状态(X)
在操作系统处理看来速度是非常快的,只要出现死亡状态就直接被释放空间了。
7.僵尸状态(Z)
是在死亡状态的前一步,首先操作系统一定会需要进程完成与否的信息,当进程任务完成了,不会直接进入死亡状态被释放空间,因为前面的进程还在继续。那么这样我们就必须标记一下此时的进程状态使得执行到它被判断为死亡状态。所以所谓僵尸进程便是子进程结束,但是父进程还未结束的状态。父进程不读取子进程的结果,操作系统不能释放空间,变为僵尸进程。
该代码我们实现子进程运行5秒后结束,但是父进程仍然进行,这样子进程没有被回收,我们就能看到僵尸进程了。
此外,针对释放空间我需要做一些解释,操作系统对内存进行清理的是进程建立的临时开辟的空间,但是不会释放PBC,因为它是操作系统动态开辟的,所以过多会引起内存变小。所以僵尸进程会导致资源泄漏,必须使用wait/waitpid接口进行等待处理。僵尸进程是已经退出运行的进程,无法被杀死(kill)。
8.孤儿进程
上面的僵尸进程是父进程不结束子进程结束;那么也会出现父进程结束,但是子进程还在进行。那么此时这个子进程就是孤儿进程,孤儿进程的父进程结束后,孤儿进程的父进程会变为原先父进程的父进程。
我们杀死父进程后,发现父进程消失了。子进程的父进程变为1了,pid为1(inti)的进程就是操作系统,也就是被操作系统“领养”了。
2.进程的优先级
1.优先级定义
定义:优先级是针对于进程本身的执行的先后顺序
目的:优先级的顺序目的是为了合理安排资源利用效率
2.Linux的优先级表现
在Linux中,优先级本质被设置为在PCB中的一个整型,整型的大小决定优先级的先后。
ps -la:即可查去进程的优先级
图中的PRI和NI一起组成了优先级,nice就是可以被调整的值,如果想改变优先级通过改变nice值即可。nice范围为[-20,19)。
公式为:优先级=老的优先级 + nice
修改优先级指令:用超管的权限做(sudo),1.输入top指令进入top,按住r 2.输入需要修改的pid 3.输入nice区间的整数即可被修改。【每次设置,老的优先级都为80】
3.优先级的其他概念
竞争性:资源有限,所以进程存在竞争,需要优先级规范。
独立性:进程的状态不会影响其他进程,拥有不同的PCB,互相不干扰
并行:多CPU,可以存在多个进程同时运行
并发:单CPU,只能有一个进程正在运行,通过切换使得不同的进程执行
4.并发的进程切换解释
在CPU中有大量的寄存器,用于实现不同功能的存储。运行的进程的PCB会被加载到寄存器中存储。CPU对进程的操作步骤就是:1.取指令 2.分析指令 3.执行
针对系列情况,寄存器的策略
1.其中pc/eip寄存器(程序计数器)专门存储下一个指令地址,所以上下段其实效率不会太低;
2.另外CPU的寄存器用于保存当前进程的数据
3.进程不会完全结束才调用其他进程,所以进程会划分为时间片,处理这些时间片
4.时间片处理完,但是进程没有完全结束,所以进程需要被存储和恢复临时数据。那么这些临时数据被存储,再需要被执行时才恢复到PCB中,这便是进程切换中的上下文数据的保护和恢复。
3.环境变量
1.定义出现
首先,我们清楚指令的本质其实都是文件的程序。不过奇怪的是,指令的输入不需要路径就可以执行;但是我们的程序需要表明是路径才可以执行,其原因就在环境变量。我们得想清楚程序运行的本质:执行文件必须让操作系统知道是哪个文件需要被执行,所以需要文件的路径;那么说明系统的指令中就有所谓的路径被记录到操作系统不需要被提醒。那么我们也可以把我们的程序拷贝到操作系统环境中去就可以不需要路径了。
环境变量:操作系统自己会到配置文件导到操作系统上下问中,使得可执行程序被找到的变量是环境变量。
2.修改查找指令的环境变量
操作1:sudo cp 程序名 usr/bin/
这样就可以把执行程序直接拷贝到操作系统中,运行不需要带路径。但是不建议这样写,因为我们的程序没进行安全检测,直接copy到操作系统会污染指令库。这样是直接的,不安全的。
PATH变量
操作2:
1.echo $PATH:查看PATH变量路径(系统指令能执行是因为指令会在这些路径下找是否存在,如果存在就可以直接执行)
which + 指定文件:得到该文件的具体路径。
2.export PATH=指定路径:将系统环境变量覆盖成现在指定的路径。(如果不想使用定义的PATH环境变量,那么就可以重新登录一次操作系统即可)
3.export PATH=$PATH:指定路径:这样就将原先的PATH和指定的路径都添加到PATH中。
3.环境变量在哪
家目录在操作系统打开时就启动了下面两个文件,两个文件中有PATH环境变量。
4.其他环境变量
$HOME:该用户的主工作目录
$HOSTNAME:操作系统名
$LOGNAME:用户名
$HISTSIZE:最大指令记录值
env:查看当前所有的环境变量
5.环境变量指令操作
echo:显示指定变量
env:显示所有变量
getenv():获取环境变量
如果env成功了,返回的值是环境变量的字符串; env失败了,返回的值是NULL
自定义环境变量名
该环境变量是局部的环境变量,它没有在env中显示,并且只能显示在设置该环境变量的用户内。所以getenv()返回的是NULL。
export:对环境变量做定义。局部的环境变量可变为全局的环境变量;也可以修改原先的环境变量。
环境变量具有全局性:全局的环境变量会被子进程继承下去。环境变量在系统进程(bash)中,但是执行进程后,fork出了子进程,子进程也拥有对环境变量的内容,这些环境变量继承与bash,以用于不同的场景。
本地变量:只会在当前进程(bash当中)内有效,没有子进程可以继承。
set:显示本地和全局的环境变量
6.环境变量的继承
命令行参数
main()函数中有三个参数main(int argc,char* argv[],char*env[]);其中我们先讨论前两个即int argc,char* argv[]。
参数的演示:
我们能清楚,其实argc获取的是一个指令的字符串的个数,而argc[]获取每个字符串的内容,并且指向结束最后还会指向NULL指针。其中命令行解释都是由shell和系统共同来做的。(那么我们能清楚命令行选项是干什么用的了,在执行命令后加不同的选项是为了实现不同的功能。)
env[]存储的就是全局环境变量的字符串。
也可以通过二级指针进行获取环境变量
**environ指向env[],若想要使用,必须先extern char** environ包含一下系统提供的二级指针。
总结进程的上下文获取环境变量的方式:
1.getenv();根据名字拿到内容(常用)
2.char* env[];
3.char** environ;