【Linux】进程状态和优先级

目录

  • 前言
  • 1、进程状态
    • 1.1、概念
    • 1.2、具体的进程状态
    • 1.3、Linux进程状态
      • 1.3.1、R运行状态(运行态)
      • 1.3.2、S/D睡眠状态(阻塞态)
      • 1.3.3、T/t停止状态
      • 1.3.3、X死亡状态
      • 1.3.4、Z(zombie)僵尸进程
  • 2、孤儿进程
  • 3、Linux进程优先级
    • 3.1、优先级概念
    • 3.2、Linux下进程优先级的操作
    • 3.3、PRI 和 NI
    • 3.4、PRI vs NI
  • 4、其他概念

前言

本篇文章进行操作系统中进程状态的学习!!!


1、进程状态

1.1、概念

凡是学进程,都要想到进程控制块(PCB) – task_struct

  • 在学习OS中的进程状态时,书上的描述为了在Linux、Windows、Android中都能说的通,往往加深了理解的难度

  • 我们可以先学习具体的Linux进程状态,然后再介绍然后再介绍OS学科的状态如何理解

  • 操作系统是计算机中的一门“哲学”,要考虑很多情况

贴几张不同的进程状态图

【Linux】进程状态和优先级_第1张图片

【Linux】进程状态和优先级_第2张图片


1.2、具体的进程状态

具体的进程状态可以分为四种:

  1. 运行态:进程只要被加载到运行队列中

如何理解进程被加载到运行队列中?

  • 运行队列也是一个对象,也可以通过描述再组织进行管理

  • 运行队列的属性其中有PCB指针,可以通过队列的性质或复杂的数据结构进行管理

  • 调度器的主要作用是在就绪队列中选择优先级最高的任务运行,如果优先级最高的任务不止一个,则选择队头的任务运行

  • 当运行队列中的进程被调度时,CPU会执行该进程的代码

【Linux】进程状态和优先级_第3张图片


  1. 终止态:进程已经终止,但还存在,只是永远不运行了,随时等待被释放

进程都已经终止了,为什么不立刻释放资源,而要维护一个终止态呢?

  • 因为释放进程的资源需要时间

  • CPU不可能一直盯着这个进程,可能还会在做其他事情,所以要维护一个终止态

  • 例子:比如你去吃饭,吃完后,叫老板结账,老板可能没回应你,他可能在给别人点餐


  1. 阻塞态:进程在等待某种资源时(非CPU资源),资源没有就绪的时候,该进程会到对应的资源等待队列中进行排队,该进程的代码并没有运行,就叫做"阻塞态"
  • 一个进程在被CPU执行的时候,用的不仅仅是CPU的资源

  • 进程可能申请更多的资源,如:磁盘、网卡、显卡、显示器资源和声卡资源等等…

  • 申请对应的资源无法满足时,是需要排队的,比如:CPU资源在运行队列中排队

  • 申请其他慢设备的资源在对应的队列中进行排队

【Linux】进程状态和优先级_第4张图片


  1. 挂起态:当内存不足时,OS会将短期内不会被调度的进程的数据和代码挪动到磁盘中的swap分区,当内存足够时,会重新加载到内存中

【Linux】进程状态和优先级_第5张图片


1.3、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 */
};

1.3.1、R运行状态(运行态)

  1. R (running)运行状态:进程是在运行中或在运行队列中

【Linux】进程状态和优先级_第6张图片

  • R状态一般是看不出来的,因为CPU的运算速度非常快,当你运行程序时,CPU就已经执行结束

  • 比如在死循环中打印hello world,进程状态一般为"S",因为CPU太快了

CPU一般在等待显示器资源就绪,所以状态一直为S

[lyh_sky@localhost lesson11]$ ls
makefile  test  test.cpp
[lyh_sky@localhost lesson11]$ cat test.cpp 
#include 
#include 
#include 
using namespace std;

int main()
{
    while (1)
    {
        cout << "hello world!!!" << endl;
        sleep(3);
    }
    return 0;
}

[lyh_sky@localhost lesson11]$ cat makefile 
test:test.cpp
	g++ test.cpp -o test
.PHONY:clean
clean:
	rm -rf test
	
[lyh_sky@localhost lesson11]$ ./test 

通过不断刷新ps指令来查看进程状态的变化:while :; do ps ajx | head -1 && ps ajx | grep ‘test’ | grep -v grep; sleep 2; echo “#############################################”; done

【Linux】进程状态和优先级_第7张图片


可以通过不断的死循环来让CPU一直不断的工作,因为死循环没有访问外设资源

[lyh_sky@localhost lesson11]$ ls
makefile  test  test.cpp
[lyh_sky@localhost lesson11]$ cat test.cpp 
#include 
#include 
#include 
using namespace std;

int main()
{
    while (1)
    {
    }
    return 0;
}

[lyh_sky@localhost lesson11]$ cat makefile 
test:test.cpp
	g++ test.cpp -o test
.PHONY:clean
clean:
	rm -rf test
	
[lyh_sky@localhost lesson11]$ ./test 

【Linux】进程状态和优先级_第8张图片


1.3.2、S/D睡眠状态(阻塞态)

  1. S (sleeping)睡眠状态:意味着进程在等待事件完成
  • 这里的睡眠也叫做:可中断睡眠(浅睡眠),因为它可以通过指令进行中断

  • 可以使用 kill 【-9】 【进程PID】进行中断

  • 睡眠状态是:该进程申请的资源已经被其他进程使用,该进程在对应的“资源等待队列中进行等待,进程中的代码没有执行

[lyh_sky@localhost lesson11]$ ls
makefile  test  test.cpp
[lyh_sky@localhost lesson11]$ cat test.cpp 
#include 
#include 
#include 
using namespace std;

int main()
{
    while (1)
    {
        cout << "hello world!!!" << endl;
        sleep(3);
    }
    return 0;
}

[lyh_sky@localhost lesson11]$ cat makefile 
test:test.cpp
	g++ test.cpp -o test
.PHONY:clean
clean:
	rm -rf test
	
[lyh_sky@localhost lesson11]$ ./test 

【Linux】进程状态和优先级_第9张图片


  1. D磁盘休眠状态(Disk sleep)
  • D状态也叫不可中断睡眠状态(uninterruptible sleep),在这个状态的进程通常会等待IO的结束

  • D状态不能通过指令进行中断,必须等它由D状态变成S状态时才能杀死

【Linux】进程状态和优先级_第10张图片

  • 经过上图可以发现,如果堆磁盘进行读写时,发生中断,会导致严重的问题

  • 所以才有了D状态,D状态就算是OS也不能对其进行释放

D状态不好模拟,但可以使用"dd指令"进行模拟

1.3.3、T/t停止状态

  1. T停止状态(stopped):
  • 可以通过发送 SIGSTOP 信号或快捷键【ctrl+z】给进程来停止(T)进程

  • 这个被暂停的进程可以通过发送 SIGCONT 信号让进程继续运行

【Linux】进程状态和优先级_第11张图片

[lyh_sky@localhost lesson11]$ ls
makefile  test  test.cpp
[lyh_sky@localhost lesson11]$ cat test.cpp 
#include 
#include 
#include 
using namespace std;

int main()
{
    while (1)
    {
        cout << getpid() << endl;
        sleep(2);
    }
    return 0;
}

[lyh_sky@localhost lesson11]$ cat makefile 
test:test.cpp
	g++ test.cpp -o test
.PHONY:clean
clean:
	rm -rf test
	
[lyh_sky@localhost lesson11]$ ./test 

可以通过kill 【-19】 【进程PID】将指定进程发生停止运行信号

【Linux】进程状态和优先级_第12张图片

kill 【-18】【进程PID】可以恢复重新运行

【Linux】进程状态和优先级_第13张图片


还有一种t (tracing stop)状态:针对gdb调试的状态

[lyh_sky@localhost lesson11]$ ls
makefile  test  test.cpp
[lyh_sky@localhost lesson11]$ cat test.cpp 
#include 
#include 
#include 
using namespace std;

int main()
{
    while (1)
    {
        cout << getpid() << endl;
        sleep(2);
        
    }
    return 0;
}

[lyh_sky@localhost lesson11]$ cat makefile 
test:test.cpp
	g++ test.cpp -o test -g
.PHONY:clean
clean:
	rm -rf test
	
[lyh_sky@localhost lesson11]$ make
g++ test.cpp -o test -g

[lyh_sky@localhost lesson11]$ gdb test

【Linux】进程状态和优先级_第14张图片


1.3.3、X死亡状态

  1. X死亡状态(dead):这个状态只是一个返回状态,你不会在任务列表里看到这个状态

1.3.4、Z(zombie)僵尸进程

概念:

注意:僵尸进程是不能被杀死的,因为已经是僵尸了,不能再死第二次!!!

  • 当一个进程退出的时候,一般不会直接进入X状态(死亡,资源可以立马被会回收),而是进入Z状态

  • 僵死状态(Zombies)是一个比较特殊的状态。当进程退出并且父进程(使用wait()系统调用)没有读取到子进程退出的返回代码时就会产生僵死(尸)进程

  • 僵死进程会以终止状态保持在进程表中,并且会一直在等待父进程读取退出状态代码

  • 只要子进程退出,父进程还在运行,但父进程没有读取子进程状态,子进程进入Z状态

  • 进程被创建出来是因为用户有任务要交给它执行,当进程退出的时候,我们不知道这个进程完成的怎么样了,一般需要将进程的执行结果告知给父进程和OS


模拟Z状态:创建子进程,子进程退出,父进程不退出(还在运行),子进程退出之后的状态就是Z

[lyh_sky@localhost lesson11]$ cat test.cpp 
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
    pid_t id = fork();
    int cnt = 3;

    if (id == 0)
    {
        while (cnt)
        {
            cout << "我是子进程,我还有" << cnt-- << "秒时间结束" << endl;
            sleep(1);
        }
        cout << "进入僵尸状态" << endl;
        // 结束子进程,并且返回0
        exit(0);
    }
    else
    {
        while (1)
        {}
    }
    return 0;
}

[lyh_sky@localhost lesson11]$ cat makefile 
test:test.cpp
	g++ test.cpp -o test -g
.PHONY:clean
clean:
	rm -rf test
	
[lyh_sky@localhost lesson11]$ ./test 

【Linux】进程状态和优先级_第15张图片


僵尸进程危害:

  • 如果没有人回收子进程的僵尸,该状态会一直被维!该进程的相关资源(task_struct)不会被释放

  • 那一个父进程创建了很多子进程,就是不回收,就会造成内存资源的浪费!因为数据结构对象本身就要占用内存,想想C中定义一个结构体变量,是要在内存的某个位置进行开辟空间!

  • 这样就会造成内存泄漏!!!


2、孤儿进程

init进程:它是内核启动的第一个用户级进程

  • 父进程如果提前退出,那么子进程后退出,进入Z之后,那该如何处理呢?

  • 父进程先退出,子进程就称之为“孤儿进程”

  • 孤儿进程被1号init进程领养,当然要有init进程回收喽

[lyh_sky@localhost lesson11]$ cat test.cpp 
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
    pid_t id = fork();
    int cnt = 3;

    if (id != 0)
    {
        while (cnt)
        {
            cout << "我是父进程,我还有" << cnt-- << "秒时间结束" << endl;
            sleep(1);
        }
        cout << "父进程退出" << endl;
        exit(0);
    }
    else
    {
        while (1)
        {}
    }
    return 0;
}

[lyh_sky@localhost lesson11]$ cat makefile 
test:test.cpp
	g++ test.cpp -o test -g
.PHONY:clean
clean:
	rm -rf test
	
[lyh_sky@localhost lesson11]$ ./test 

【Linux】进程状态和优先级_第16张图片


3、Linux进程优先级

3.1、优先级概念

进程优先级和权限的区别?

  • 进程优先级是:进程获取外设资源的先后顺序问题

  • 权限是:拥有者、所属组和other是否可以进行读写执行操作

  • 它们的区别是:在学校中,我们去吃饭,食堂分教师和学生,我们不能去教师食堂打饭,这就是权限。我们打饭时,需要排队,排在前面可以先打到饭,后面的也一样可以打到饭,这就是优先级


概念:

  • cpu资源分配的先后顺序,就是指进程的优先权(priority)

  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能

  • 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能


为什么要存在进程优先级呢???

  • 排队的本质就是确认进程的优先级

  • 内存里面永远都是进程占大多数,而资源是少数(外设:磁盘、网卡、显卡…)

  • 进程竞争资源是常态,OS要确认进程的先后循序,不然就乱套了


3.2、Linux下进程优先级的操作

使用【ps -al】指令查看进程更多的属性(包含进程优先级):

  • top指令

  • 进入top后按“r”–>输入进程PID–>输入nice值

[lyh_sky@localhost lesson11]$ ls
makefile  test  test.cpp
[lyh_sky@localhost lesson11]$ cat test.cpp 
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
    while (1)
    {
        cout << "hello world!!!" << endl;
        sleep(2);
    }
    return 0;
}
[lyh_sky@localhost lesson11]$ cat makefile 
test:test.cpp
	g++ test.cpp -o test -g
.PHONY:clean
clean:
	rm -rf test
[lyh_sky@localhost lesson11]$ ./test 

【Linux】进程状态和优先级_第17张图片

我们很容易注意到其中的几个重要信息,有下:

  • UID : 代表执行者的身份

  • PID : 代表这个进程的代号

  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号

  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行

  • NI :代表这个进程的nice值


3.3、PRI 和 NI

  • PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小进程的优先级别越高

  • NI就是nice值,其表示进程可被执行的优先级的修正数值

  • PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为: PRI(new) = PRI(old) + nice

  • 当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行

  • 调整进程优先级,在Linux下,就是调整进程nice值

  • nice其取值范围是-20至19,一共40个级别,调整NI时,会重新变成初始值80,然后+NI值

例如PRI:70 NI:-10,把NI更改成10时,PRI = 80 + 10 = 90

在root用户下,使用top指令修改进程优先级:

[lyh_sky@localhost lesson11]$ ls
makefile  test  test.cpp
[lyh_sky@localhost lesson11]$ cat test.cpp 
#include 
#include 
#include 
#include 
using namespace std;

int main()
{
    while (1)
    {
        cout << "hello world!!!" << endl;
        cout << "我的pid是: " << getpid() << endl;
        sleep(2);
    }
    return 0;
}
[lyh_sky@localhost lesson11]$ cat makefile 
test:test.cpp
	g++ test.cpp -o test -g
.PHONY:clean
clean:
	rm -rf test
[lyh_sky@localhost lesson11]$ ./test 

进入top指令后输入r,然后回车,然后输入需要修改进程优先级的pid

【Linux】进程状态和优先级_第18张图片

输入pid后回车,接着输入NI值,就能修改进程优先级了

【Linux】进程状态和优先级_第19张图片

3.4、PRI vs NI

  • 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化

  • 可以理解nice值是进程优先级的修正修正数据


4、其他概念

  1. 竞争性:系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级

  1. 独立性:多进程运行,需要独享各种资源,多进程运行期间互不干扰
  • 比如:我们在下载东西时,同时打开浏览器进行浏览,当浏览器挂掉了,是不会影响下载的,反之下载挂掉了,也不会影响浏览器

  • 进程具有独立性,不会因为一个进程挂断或者出现异常,而导致其他进程出现问题


  1. 并行:多个进程在多个CPU下,分别同时进行运行,这称之为并行

【Linux】进程状态和优先级_第20张图片


  1. 并发:多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

【Linux】进程状态和优先级_第21张图片

操作系统,就是简单的根据队列来进行先后调度的吗?有没有可能突然来了一个优先级更高的进程?

  • 操作系统中有二种内核,分为“抢占式内核”和“非抢占式内核”

  • 当正在运行的低优先级进程,如果来了一个优先级更高的进程,调度器会直接把正在执行的进程从CPU上剥离,放上优先级更高的进程,这就是“进程抢占”(抢占式内核)


  1. 进程上下文:进程在运行中产生的各种寄存器数据,就叫做进程的硬件上下文数据
  • 当进程被剥离:需要保存上下文数据

  • 当进程恢复的时候:需要将曾经保存的 上下文数据恢复到寄存器中

【Linux】进程状态和优先级_第22张图片

你可能感兴趣的:(Linux,linux,运维,服务器)