您的位置  > 互联网

(Linux基础知识)Linux进程优先级五、进程切换

流程的不同状态本质上是为了满足不同的操作场景而设计的。

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继续运行时会重新加载并恢复这些数据。