流程的不同状态本质上是为了满足不同的操作场景而设计的。
1. 运行队列
进程如何在CPU上运行:CPU在内核上维护一个运行队列来管理进程。 将进程放入队列本质上就是将进程的结构体对象放入运行队列。
2、运行状态
进程PCB在运行队列中处于运行状态。 并不代表进程正在运行,也就是运行状态。
状态是进程内部的一个属性,所有属性都在PCB中
进程不仅意味着占用CPU资源,还可能随时需要外设资源。
该进程不在运行队列中,无法直接调度该进程,而是在等待外设资源的状态。 本质就是将对象放在不同的队列中!
综上所述,所谓进程的不同状态本质上是指进程处于不同的队列中,等待某些资源。
如果系统中有很多进程,进程短期内不会被调度,代码和数据短期内不会被执行。 如果此时内存空间不足,操作系统可以将代码和数据暂时保存到磁盘上,节省一些空间。 ,进程暂时挂起,这就是挂起状态。
关于阻塞状态和挂起状态,阻塞并不一定意味着挂起,挂起一定意味着阻塞。
这些都是概念性的,具体在Linux下是什么样子的呢?
2.Linux进程状态
为了理解正在运行的进程的含义,我们需要了解进程的不同状态。 一个进程可以有多种状态(在Linux内核中,进程有时被称为任务)。源码中定义了以下状态
代码语言:
复制
/*
* The task state array is a strange "bitmap" of
* reasons to sleep. Thus "running" is zero, and
* you can test for combinations of others with
* simple bit tests.
*/
static const char * const task_state_array[] = {
"R (running)", /* 0 */
"S (sleeping)", /* 1 */
"D (disk sleep)", /* 2 */
"T (stopped)", /* 4 */
"t (tracing stop)", /* 8 */
"X (dead)", /* 16 */
"Z (zombie)", /* 32 */
};
R运行状态()、S睡眠状态()、D盘睡眠状态(Disk sleep)、T停止状态()、X死亡状态(dead)
我们看一下Linux下的运行状态(R)是什么样的:
图像-
创建.c:
图像-
图像-
编辑一下:
图像-
图像-
这是因为需要访问外设显示,而外设速度比较慢,需要等待很长时间(相对于CPU)。
我们可以看一下T状态
图像-
对于S来说,是浅睡眠,可以终止。 D是深度睡眠,不能被操作系统杀死。 只能自己断电唤醒来解决。 这里简单看一下。
状态:
图像-
这也是暂停状态,stop表示进程正在被跟踪
3、两个特殊工艺
当进程退出时,该进程对应的资源并不能立即释放!保存一段时间,让对应的父进程/操作系统读取。
1.僵尸进程
僵尸状态( state)是一种比较特殊的状态。当进程退出并且父进程没有读取到子进程退出的返回码时,就会出现僵尸()进程。
下面,我们可以通过具体的例子来了解一下僵尸进程。 进程退出但未被回收(父进程,OS)。 我们可以创建一个子进程,这样父进程不退出,子进程正常退出(exit(1)):
图像-
监控脚本命令:
代码语言:
复制
while :; do ps axj | head -1 && ps axj | grep myprocess | grep -v grep; sleep 1; done
图像-
右侧运行一段时间后出现Z状态:
图像-
表示无效,即进程已经死亡但还没有被回收。终止左侧,执行上面监控的命令。 上述过程将不再存在。 这是因为当父子进程终止时,操作系统会自动回收它们。
图像-
这是一个僵尸进程。 内存泄漏不仅仅体现在\new中,系统中也存在。
僵尸进程的危险
进程的退出状态必须被维护,因为它需要告诉关心它的进程(父进程)我是如何完成你给我的任务的。如果父进程从不读取,子进程将永远在Z状态。 维护退出状态本身就需要数据维护,同时也是进程的基本信息,所以保存在(PCB)中。 换句话说,Z状态永远不会退出。 PCB总是要维护父进程并创建许多子进程。 如果不回收的话,会造成内存资源的浪费,因为数据结构对象本身就占用内存。 想想在C中定义一个结构体变量(对象),需要在内存的某个地方开辟空间。
2. 孤儿进程
父进程先退出,子进程称为“孤儿进程”。 孤儿进程被1号init进程采用,并被init进程回收。
废话不多说,我们直接通过一小段代码来看一下:
图像-
首先我们看一下z状态(杀死子进程):
图像-
现在重新启动进程(杀死父进程):
图像-
父进程结束,看不到它的僵尸状态:父进程也有父进程,它们都是bash的子进程,所以bash进程会回收父进程的资源。
图像-
这时30418就变成1:1对应的操作系统了。 1号采用的子进程是孤儿进程。
可以肯定的是父进程先退出。 子进程将被操作系统采用(1号进程)。 这是为了在子进程退出时回收相应的僵尸进程,并对子进程进行管理。
收养过程就是孤儿过程。
图像-
同时,子进程之前的状态是S+,现在变成了S。如果前台进程创建的子进程成为孤儿,那么它会自动成为后台进程(无法用ctrl+杀死)此时C,只能用kill解决)
图像-
4. 进程优先级 1. 优先级概念
对优先级的理解决定了能否按顺序获取资源。优先级高的先获取,反之亦然。
存在原因:资源太少,需要分配
CPU资源分配的顺序是指进程的优先级()。 优先级较高的进程拥有优先执行权。 配置进程优先级对于多任务环境中的Linux非常有用,可以提高系统性能。
优先级的本质是PCB中的一个/几个整数
2.查看系统进程
在linux或unix系统中,使用ps –la命令将输出类似以下内容:
图像-
UID:代表执行者的身份。 PID:代表该进程的代号。 PPID:表示这个进程是从哪个进程发展而来的,即父进程的代号。 PRI:表示该进程可以执行的优先级。 值越小。 越早执行(就像性能排名一样,越小越好) NI:代表这个进程的nice值
3.PRI和NI
Linux 中的优先级由两个整数确定:PRI() 和 NI(nice)
在Linux下,可以认为最终优先级=old优先级+NI。
注意:Linux下旧的默认优先级值为80! 而NI,即nice值,也有一个取值范围。 取值范围为[-20,19],表示优先级的取值范围为[80-21,80+19]。 稍后我们将演示nice值的取值范围。
Linux下,进程的优先级是在运行过程中调整的。 调整策略是通过改变nice值来完成的,也就是说会受到nice值的影响(但一般情况下是不会修改的)。
但大多数情况下,nice值是默认值,即0:
图像-
图像-
这里的PRI优先级是80,下面我们可以更改它
命令改变很好
步骤1:须藤顶
第二步:输入top后输入r然后输入进程的pid(进入进程)并输入要修改的nice值。
图像-
图像-
这里仍然是80,让我们使用top来更改它(输入sudo top,然后输入r):
图像-
图像-
当输入要修改的值时,以-100为例,会出现以下情况(最终变成-20):
图像-
这里,改成100后,出现以下情况(最终变成19):
图像-
注意:调整优先级并不意味着可以随便调整。 这是操作系统不允许的,会导致调度不平衡。所以有一定的取值范围
Nice的取值范围是[-20,19],共40个数字
以上就是Linux优先级的内容。 我们在这里简单介绍一下。
5.特点
竞争:系统进程较多,但CPU资源只有很少,甚至1个,因此进程之间存在竞争。为了高效地完成任务,更合理地竞争相关资源,实现了优先级独立:当多个进程运行时,各种资源需要独占共享,多进程运行时互不干扰。 并行性:多个进程同时在多个CPU上单独运行。 运行起来,这叫并行并发:多个进程在一个CPU下使用进程切换,在一段时间内,可以提升多个进程,这叫并发。
这里的父进程和子进程的独立性还存在吗? 是的
代码语言:
复制
int main()
{
pid_t id = fork();
if(id == 0)
{
while(1)
{
printf("this is child process,pid: %d,ppid:%d\n",getpid(),getppid());
sleep(1);
int *p = NULL;
*p = 100;//野指针
}
}
else
{
while(1)
{
printf("this is parent process,pid:%d,ppid:%d\n",getpid(),getppid());
sleep(1);
}
}
}
图像-
图像-
子进程崩溃不影响父进程
5. 进程切换 1. 并发
多个进程使用同一个CPU不断切换进程,让单CPU计算机在一段时间内同时推进多个进程代码的现象称为并发。
利用进程切换,不同的进程可以运行一段时间内的代码并同时前进。
2. 如何切换进程
CPU中有一组硬件寄存器。 宏观上,寄存器分为用户可见的和用户不可见的。
当计算机调度一个进程时,CPU会将进程的PCB地址加载到寄存器中。 也就是说CPU中有一个寄存器只能找到进程的PCB地址。
CPU中有一个eip寄存器(PC指针),它指向当前执行的指令之后的下一条指令的地址。
进程运行时,会产生很多临时数据,但这些临时数据只属于当前进程。 虽然CPU内部只有一套寄存器硬件,但寄存器中保存的数据只属于当前进程。 换句话说,寄存器硬件不是寄存器硬件。 这是两件不同的事情。 寄存器是所有进程共享的,但是寄存器中的数据是每个进程私有的。
时间片启发
进程在运行时会占用CPU,但直到进程结束时才会占用CPU。 该过程有自己的时间片! 由于时间片的存在,进程可能还没执行完就被下掉了。 这时候问题就出现了:这个进程下次如何返回CPU继续运行:
进程切换时,需要先进行上下文保护。 这里的上下文指的是CPU中的寄存器数据,而不是寄存器。 简单理解就是临时数据保存到PCB上,当进程恢复运行时,需要上下文保护。 对于恢复,进程返回CPU继续运行时会重新加载并恢复这些数据。