Linux进程概念

本文介绍了冯诺依曼体系下的CPU和内存功能,阐述了操作系统的概念及其在进程管理、资源调度中的角色。详细讨论了进程的概念,包括进程状态(就绪、运行、阻塞)、创建(如fork()函数)、进程间通信以及如何处理僵尸和孤儿进程。此外,还涉及环境变量的设置和作用。
摘要由CSDN通过智能技术生成

#一、 进程概念

1、1 冯诺依曼体系

在这里插入图片描述

1、1、1 中央处理器:CPU

  • 功能:算术运算与逻辑运算(与、或、非门)

1、1、2 储存器:内存

  • 功能:储存数据,但是不能持久化的保存
  • 结论:
    • 1、所有数据都是采用二进制进行储存(通过电流的高低电平模拟二进制数据);
    • 2、运算产生的数据都是存储在内存中。
  • 扩展:
    • 1、一个CPU在同一时刻只能计算一组数据、芯片的性能取决于制作工艺;
    • 2、4核8C:代表4个物理CPU,8个逻辑CPU;
    • 3、交替运算(多任务处理):CPU在同一时间内执行多个程序或任务的能力。在操作系统中,CPU会通过轮流执行不同的程序,每个程序执行一小段时间后,就会被暂停,CPU开始执行另一个程序,直到所有程序都执行完毕。

1、2 操作系统的概念与定位

1、2、1 什么是操作系统

  • 简单来说: 操作系统:操作系统内核+一堆程序
  • 操作系统概念:
    • 操作系统是计算机系统中的核心软件之一,它是管理计算机硬件和软件资源,提供用户和应用程序访问计算机系统资源的程序集合。
    • 任何计算机系统都包含一个基本的程序(一堆代码)集合,成为操作系统(OS);
  • 操作系统内核:代码程序,代码的作用就是(进程管理、内存管理、文件管理、驱动管理等);
  • 一堆应用:依附在操作系统内核上完成某些功能的软件,例如、QQ、微信
    在这里插入图片描述

1、2、2 操作系统在做什么事

  • 操作系统在管理计算机的软硬件资源;
  • 硬件资源:CPU、内存、硬盘、网卡、显示器;
  • 软件资源:进程资源、驱动程序

1、2、3 操作系统怎样完成这些事情的

  • 通过管理。
  • 管理 = 描述 + 组织
  • 代码角度:
    • 描述:结构体;
    • 组织:双向链表;

1、2、4 操作系统组织结构图

在这里插入图片描述

1、2、5 系统调用&库函数

  • 系统调用:操作系统提供的函数,被称为系统调用函数。
  • 库函数:C标准库提供的函数、被称之为库函数。库函数的代码实现当中调用了系统调用函数。
    在这里插入图片描述

1、3进程概念(PCB)

1、3、1什么是程序?什么是进程?

  • 程序:源代码经过编译产生的可执行文件,这个文件是静态的。例如、(.out)
  • 进程:程序运行起来的实例,是动态在运行的。

1、3、2操作系统是如何管理进程的

  • 进程的管理 = 描述(PCB)+组织的方式(双向链表)

1、3、3描述(PCB){task_struct{…}}

  • 进程标识符:在当前机器能够唯一表示一个进程
  • 进程号(PID:process ID):是操作系统为每个正在运行的进程或线程分配的唯一标识符,一般来说,一个进程由OS自动分配空的进程号。
  • 如何查看进程号:
    • 命令:
      ps aux 加上管道符号和过滤,拿到自己想要的信息;
      或者ps -ef

    • 函数:
      pid_t getpid(void):谁调用获取谁的进程号;
      pid_t getppid(void):谁调用获取谁的父进号;

ps aux |grep <name>
ps -ef |grep <name>

在这里插入图片描述

在这里插入图片描述

进程状态

  • 进程状态:就绪、运行、阻塞;
  • 从CPU角度理解:
    在这里插入图片描述

机器当中的进程很多,CPU的数量远远小于进程的数量,那么进程是如何获取CPU资源的?
重点:一个进程想要向后执行自己的代码,必须拥有CPU资源进行计算(执行代码)

  • 操作系统调度进程获取CPU资源:
    • 调度策略:
      • 先来先服务:先到先服务。在服务需要排队等候的情况下,服务员或服务机构按照顾客的到达先后顺序,依次提供服务。
      • 短作业优先:该算法按作业执行所需的时间来排序,先执行最短的作业,以此类推。
      • 长作业优先:当有多个作业需要完成时,长作业应该优先完成。
      • 优先级优先:优先级高的操作会先被处理,而优先级低的操作则可能被推迟甚至被忽略。
      • 时间片轮转(轮询调度):将所有正在运行的进程分配相同的时间片(毫秒级别:5-800),一旦时间片用尽,操作系统就会将该进程暂停并将CPU分配给下一个进程,直到所有进程都被处理一遍。
  • 运行状态:进程获得CPU资源,占用CPU,并在CPU上运行(进程正在使用CPU来执行自己的代码);
  • 就绪状态:进程已经具备运行条件,但CPU还没有分配过来(进程已经将运行前的准备工作全部准备好了,就等着操作系统调用占用CPU);
  • 阻塞状态:进程因等待某件事的发生暂时不能运行;例如:等待IO输入、调用某些阻塞接口;
    在这里插入图片描述

插入:

  • 进程是抢占式执行 狼(进程)多肉(CPU)少
    在计算机的CPU数量少,进程多的情况下(常态),操作系统在调度的时候要做到雨露均沾。让每一个进程都能运行上,但是操作系统在调度的时候,是从就绪队列当中获取进程,进行运行。(进程准备好了,谁准备好了,原则上就可以调度谁),进程为了能够执行自己的代码,都是抢占式执行,不会互相谦让。
    “狼多肉少”========>产生进程的不同状态的主要原因之一;

  • 并发:多个进程在一个CPU下,采用进程切换的方式,各自独占CPU运行自己的代码(交替运行),让多个进程都得以推进,称之为并发。
    在这里插入图片描述

  • 并行:多个进程加粗样式多个CPU下,同时运行各自的代码,称为并行。
    在一个多核CPU的机器中:并发并行是混合存在的。

  • 细分的进程状态:(重点

    • R:运行状态:
      处于R状态的进程,有可能在执行代码,有可能在运行队列(就绪队列);
    • S:可中断睡眠状态:
      进程正在睡眠(被阻塞),等待资源到来时唤醒,也可以通过其他进程信号或时钟中断唤醒进入运行状态;
    • D:不可中断睡眠状态:
      通常等待一个IO结束(也就是输入输出的结束);
    • T:暂停状态(Ctrl+Z):
      在Linux下,Ctrl+z不是结束进程,而是暂停。终止进程:Ctrl+c;
    • t:跟踪状态:
      调试程序的时候可以看到;
    • X:死亡状态:
      这个状态是用户看不到的,在PCB被内核释放的时候,进程会被置为X,紧接着进程就推出了;
    • Z:僵尸状态(重点):(后面会详细说明)
      当一个进程已经完成了自己的任务,但其父进程却还没有执行完“回收”该进程的操作,因此该进程被称为僵尸进程。
  • 程序计数器:
    保存程序下一条执行的指令(重点

    • CPU 进行运算的时候,是按照汇编指令进行运算的。
  • 上下文信息:
    保存寄存器当中的内容(重点

  • 在多进程的操作系统当中,进程切换(操作系统调度进程,在获取CPU之后),进行恢复现场(通过程序计数器和上下文信息),继续执行后面的代码。

  • CPU与内存的抽象关系图:
    在这里插入图片描述

  • PCB结构体:

 struct task_struct{
 //进程标识符
 //进程状态
 //程序计数器
 //上下文指针
 //内存指针
 //记账信息
 //IO信息
 //这些只是冰山一角
 }
  • 内存指针:指向”程序地址空间“(重点);
    在这里插入图片描述

  • 记账信息:记录使用CPU时长,内存大小;

  • IO信息:保存进程打开文件的信息;

    • /pro/[pid]:进程存在于磁盘的文件信息,一个进程是一个以pid命名的文件夹;
      例如:
    • 一个进程被创建出来,默认可以使用标准输入、标准输入、标准错误(stdin、stdout、stderr),原因就是在进程创建之初,默认打开了这三个文件(Linux当中一切皆文件)
      在这里插入图片描述
  • 扩展话题:

    • 结论一: 以32位操作系统为例,程序地址空间当中的4G空间,每一个字节都有一个地址编号(0x00000000~0xFFFFFFFF);
    • 大端和小端:
      • 小端:低位存在低地址;
      • 大端:低位存在高地址;
      • x86体系的机器都是小端机器;

1、3、4组织(双向链表)

在这里插入图片描述

1、3、5创建子进程

1、fork()
  • 头文件<unistd.h>
#include<unistd.h>
pid_t fork(void)
  • 作用:让一个正在运行的进程调用该函数,可以让运行的进程创建出来一个子进程。两者是父子关系;
  • 参数:无参;
2、fork()的返回值
 RETURN VALUE:
  Upon successful completion, fork() shall return 0 to the child process and shall return the process ID of the child process to the parent process. Both processes shall continue to execute from the fork() function. Otherwise, -1 shall be returned to  the  parent  process,  no child process shall be created, and errno shall be set to indicate the error.
  • 失败:返回-1;
  • 成功:返回两次,
    父进程返回大于0的数字;
    子进程返回等于0
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 
  4 int main()
  5 {
  6   printf("begin create sub process....\n");
  7   /*创建子进程*/
  8   fork();
  9   printf("end....\n");                                                
 10   return 0;
 11 }

在这里插入图片描述

3、原理
  • 子进程拷贝父进程的PCB:
    • 结论:
      1、父子进程代码共享,因为子进程拷贝父进程的PCB,所以拥有相同的代码;
      2、数据独有(栈的数据,堆区的数据):因为各自有各自的程序地址空间;
      3、父进程将子进程创建出来后,子进程就是一个独立的进程,被操作系统独立进行调度(调度的时候和父进程没有半毛钱关系),并且父子进程还是抢占式执行;引申含义:父进程创建子进程成功之后,父子进程谁先被调度谁被后调度,还是不一定的;
  • 引出问题:子进程被创建出来之后,到底是从main函数开始执行呢,还是从fork之后开始运行呢,为什么?
4、子进程从哪一行开始执行?
  • 从头开始执行(×,子子孙孙无穷无尽也)

  • 从fork对应的代码行开始执行(×,子子孙孙无穷无尽也)

  • 从fork 之后开始运行;
    在这里插入图片描述

  • 原理解释:
    程序计数器:保存程序要执行的下一条指令;

5、使用fork()使两个进程执行不同的代码
 1: test_fork.c  ⮀                                                            ⮂⮂ buffers 
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 
  4 int main(){
  5   pid_t i= fork();
  6   if(i<0){
  7     printf("create error");
  8   }
  9   else if (i==0){                                                                      
 10     printf("I am child process ,pid=%d,ppid=%d\n",getpid(),getppid());
 11   }
 12   else{
 13     printf("I am father process,pid=%d,ppid=%d\n",getpid(),getppid());
 14   }
 15   while(1){
 16     sleep(1);
 17   }
 18   return 0;
 19 }

在这里插入图片描述

6、扩展: 正常在命令行当中启动的进程,他的父进程是谁呢?

在这里插入图片描述

shell命令以及运行原理:
  • Linux严格意义上说是一个操作系统,我们称之为“核心(kernel)”,但我们一般用户,不能直接使用kernel。而是通过kernel的“外壳”程序,也就是所谓的shell ,来与kernel沟通。如何理解?

  • 从技术角度:
    Shell的最简单定义:命令行解释器(command Interperter)主要包含:
    1、将使用者的命令翻译给核心(kernel)处理;
    2、同时,将核心的处理结果翻译给使用者。

  • 对比于windows GUI:我们操作windows不是直接操作Windows内核,而是通过图形接口,点击,从而完成我们的操作。

  • shell对于Linux:有相同的作用,主要是对于我们的指令进行解析,指令解析给Linux内核,反馈结果在通过内核运行出结果,通过shell解析给用户。

  • 命令行解释器本质也是一个进程!!!!!

  • 在命令行当中启动一个进程,原理是:

    • 命令行解释器的进程,创建子进程,让子进程进行程序替换(进程控制),替换为目标程序。

1、3、6 僵尸进程&僵尸状态

1、什么是僵尸进程
  • 僵尸进程:已经完成执行的子进程,但是其父进程尚未对其进行善后处理,导致进程表中仍存在该进程的记录,但是已经不再具有任何功能和作用的进程。
2、模拟代码
kill <pid>       // 终止一个正在运行的进程
kill -9 <pid>    //强杀一个进程
//与进程信号强相关
4 int main()
  5 {
  6   pid_t ret=fork();
  7   if(ret<0)
  8   {
  9     printf("crete failed....\n");
 10     return 0;
 11   }
 12   else if(0==ret)
 13   {
 14     //子进程
 15     //sleep(1);
 16     printf("i am child process pid=%d,ppid=%d\n",getpid(),getppid(    ));
 17   }
 18   else
 19   {
 20     printf("i am father process pid=%d,ppid=%d\n",getpid(),getppid    ());
 21     while(1)
 22     {                                                             
 23        sleep(1);
 24      }
 25   }
 26   return 0;
 27 }

在这里插入图片描述

  • 使用kill命令
    在这里插入图片描述
  • 不能让一个已经“死”了的进程再“死”一次
3、原因
  • 子进程先于父进程退出,子进程在退出的时候,会告知父进程(信号),父进程接收到信号之后是忽略处理,父进程并没有回收子进程的退出状态信息,从而导致子进程变成了僵尸进程。
  • 退出状态信息:
    退出码、退出信号、core dump标志位;
4、僵尸进程的危害
  • 子进程的PCB(struct task_struct{…})没有被操作系统内核释放,从而导致内存的泄露。
5、如何解决僵尸进程
  • 1、终止其父进程(孤儿进程,不推荐,成本太高)
kill <父进程PID>`
kill -9 <父进程pid> 

在这里插入图片描述

  • 2、重启操作系统(简单,粗暴,不推荐,成本太高)
  • 3、进程等待(进程控制)

1、3、7 孤儿进程

1、产生原因
  • 父进程先于子进程退出,子进程就变成了孤儿进程;
2、代码模拟产生孤儿进程
  1 #include<stdio.h>
  2 #include<unistd.h>
  3 
  4 int main(){
  5   pid_t res=fork();
  6   if(res<0){
  7     printf("create error!");
  8     return 0;
  9   }else if (res==0){
 10     while(1){
 11     printf("I am child process,pid=%d,ppid=%d\n",getpid(),getppid());
 12     sleep(3);
 13     }
 14     }else{                                                                                                                                                                              
 15     printf("I am father process.\n");
 16     while(1);
 17   }
 18   return 0;
 19 }

在这里插入图片描述

3、孤儿进程的退出信息由谁回收ne?
  • 由一号进程(养父)回收:该孤儿进程在退出的时候,退出状态信息由1号进程进行回收;
  • 一号进程:操作系统的init进程,操作系统很多进程都由该进程创建出来的。
插入:
  • 在命令行当中运行的进程,一般情况下都是阻塞bash进程的运行的。
  • 前台进程:阻塞bash运行的进程称之为前台进程,反之,称之为后台进程
  • 前台程序运行时+&=====>后台进程
  • 后台进程+“fg”=======>前台进程
    在这里插入图片描述
4、 孤儿进程有危害ma?
  • 孤儿进程没有任何危害,1号进程回收孤儿进程的退出状态信息;
    • ** 有孤儿进程,没有孤儿状态!!!!**

1、3、8 环境变量

1、什么是环境变量
  • 环境变量:在操作系统中用来指定操作系统运行的一些参数;换句话说,操作系统通过环境变量来找到运行时的一些资源。
  • 例如,链接的时候,帮助连接器找到动态库(标准库的);(用户自己编译的动态库,需要自己指定环境变量),执行命令的时候,帮助用户找到该命令在哪一个位置,例如我们常用的ls。

在这里插入图片描述

2、常见的一些环境变量
  • PATH:指定可执行程序的搜索路径,程序员执行的命令之所以能找到,这个环境变量起到的作用(汗马功劳)
  • which <命令>:返回该命令的可执行文件路径
    在这里插入图片描述
  • HOME:登录到Linux 操作系统的用户家目录
  • shell:当前命令行解释器,默认是“/bin/bash”
    在这里插入图片描述
3、查看当前的环境变量

- env
环境变量名称:环境变量的值(使用“:”进行间隔)
在这里插入图片描述

- echo $<环境变量名称>
可以查看单个环境变量对应的值
在这里插入图片描述

4、环境变量对应的文件
  • 系统级文件:针对于各个用户都起作用(root用户修改),强烈不推荐修改系统级的环境变量文件,因为会影响其他用户
    /etc/bashrc
  • 用户级别环境变量文件:推荐大家修改这两个文件,只对自己用户的环境变量做出修改,只影响自己,这两个文件在当前用户的家目录下面,是隐藏文件。
    ~/.bashrc
    ~/.bash_profile
    ~/.bash_profile文件包含/.bashrc文件;
    ~/.bashrc包含/etc/bashrc文件;
  • eg:
    在用户hty_dsb下三个文件的关系:
    • ~/.bashrc
      • ~/.bash_profile
        • /etc/bashrc
5、修改环境变量
  • 命令范式:export <环境变量名称>=<$环境变量名称>:<新添加的环境变量的内容>

  • export PATH=/home/hty_dsb

    • 结果:PATH=/home/hty_dsb
      在这里插入图片描述
  • export PATH=$PATH:/home/hty_dsb

    • 结果:在原先环境变量的内容保持不变的情况下,增添新内容/home/hty_dsb
      在这里插入图片描述
  • 命令行中直接修改:(特点:临时生效)

    • 如果是新增,可以不要<$环境变量名称>,及export <环境变量名称>=<新添加的环境变量的内容>;
    • 如果是修改老的:必须加上<$环境变量名称>,否则之前的环境变量的值就找不到了。
      在这里插入图片描述
  • 文件中修改:

    • 特点:修改完毕之后,不会立即生效,需要配合source <环境变量文件名称>,永久生效;
    • 新增:在文件末尾直接添加:export <环境变量名称>=<新添加的环境变量的内容>:<新添加的环境变量的内容>,用:分隔每个内容;
    • 如果修改老的:在老的后面添加“:<新添加的环境变量的内容>”。
      在这里插入图片描述在这里插入图片描述
      在这里插入图片描述
      在这里插入图片描述
  • 扩展内容:

    • 让自己的可执行程序在命令行当中运行的时候,不需要加上“./”;
    • 操作方法:将可执行程序的路径配置到PATH环境变量当中。
    • “./”的作用:告诉bash,要执行程序在当前路径下。
6、环境变量的组织方式
  • 环境变量是以字符指针数组的方式进行组织的,最后的元素以NULL结尾(当程序拿到环境变量的时候,读取到NULL,就知道读取完毕了)
    在这里插入图片描述
7、代码获取环境变量
1、main函数的参数
  • int main(int argc,char* argv[],char* env[])
  1 #include<stdio.h>
    2 #include<stdlib.h>                                                                                                                                                                    
W>  3 int main(int argc,char* argv[],char* envp[])
    4 {
    5   for(int i=0;envp[i]!=NULL;i++)
    6   {
    7     printf("---------[%s]\n",envp[i]);
    8   }
    9   return 0;
   10 }

在这里插入图片描述

  • 扩展知识:命令行参数
    • eg:
      ls -a -l : -a -l ,就是命令行参数;
 1 #include<stdio.h>
  2 #include<string.h>
  3
  4 int main(int argc,char* argv[])
  5 {
  6   for(int i=0;i<argc;i++)
  7   {
  8     if(strcmp("-a",argv[i])==0)
  9     {                                                                                                                                                                                   
 10       printf("-a read.....\n");
 11     }
 12   }
 13   return 0;
 14 }

在这里插入图片描述

2、environ
  • extern char **environ:这个是全局的外部变量,在lib.so(c标准库当中定义的)当中定义,使用的时候,需要用extren关键字
  1 #include<stdio.h>
  2 #include<string.h>
  3 #include<stdlib.h>
  4 
  5 int main()
  6 {
  7   extern char** environ;
  8   for(int i=0;environ[i]!=NULL;++i)
  9   {
 10     printf("-------[%s]\n",environ[i]);                                                                                                                                                 
 11   }
 12   return 0;
 13 }

在这里插入图片描述

3、getenv
  • #include<stdlib.h>
    • char *getenv (const char *name);
      • 参数:环境变量名称;
      • 返回值:环境变量的值,没有找到返回NULL;
        -### 1、3、9 程序地址空间
  5 int main()
  6 {
  7   printf("----HOME%s\n",getenv("HOME"));                                                                                                                                                
  8   return 0;
  9 }

在这里插入图片描述

1、3、9进程虚拟地址空间

1、图示

在这里插入图片描述

2、代码
  • 步骤:

    • 1、定义一个全局变量
    • 2、创建一个子进程
    • 3、父子进程分别打印全局变量的值,打印全局变量的地址
    • 4、子进程修改全局变量,继续观察

    在这里插入图片描述

在这里插入图片描述

  • 变量内容不一样,所以父子进程输出的变量绝对不是同一个变量
  • 地址值是相同的,说明,该地址绝对不是物理地址!
  • 在Linux地址下,这种地址叫做虚拟地址
问题:为啥操作系统费劲的要搞出来一个虚拟地址呢?
  • 解决内存碎片问题 ,提高内存使用率
3、虚拟地址
  • 我们在用C/C++语言所看到的地址,都是虚拟地址!物理地址用户一概看不到,由操作系统统一管理;
  • 操作系统需要负责将程序当中的虚拟地址,转化为物理地址。
4、进程的虚拟地址空间
  • 操作系统为每一个进程都虚拟出来一个4G的虚拟地址空间(32位操作系统),程序在访问内存的时候,使用的是虚拟地址进行访问。
  • 既然是操作系统虚拟出来的地址,所以并不能直接存储数据,存储数据还是在真实的物理内存当中。
  • 所以OS需要将虚拟地址转化为物理地址进行访问(页表)。
扩展
  • 为什么操作需要给每个进程都虚拟出来一个进程地址空间呢?为啥不直接让进程访问物理内存,这样不是更加快一点
    • 原因:因为各个进程访问同一个物理地址空间,就会造成不可控。在有限的内存空间中,进程是不清楚哪一个内存被其他进程使用,那些内存是空闲的,没有办法知道。所以,在这种场景下,冒昧的使用,一定会导致多个进程在访问物理内存的时候,出现混乱;所以,内存由操作系统统一管理起来,但是又不能采用预先直接分配内存的方式,给进程分配物理内存。因为操作系统也不清楚进程能使用多少内存,使用多久。所以,操作系统就虚拟给每个进程分配了4G的地址(虚拟地址)。
    • 当进程真正要保存数据,或者申请内存的时候,操作虚拟地址,让操作系统再给进程进行分配。这样就比较合理(同时也会节省很多空间,毕竟谁用才分配真正的物理内存)。
  • 每个进程都无感的使用拿到的虚拟地址,背后就是操作系统进行了转换(就是后面说到的页表映射)。
  • 为什么32位操作系统,给进程分配的是4G的虚拟地址空间?
    • 因为32位操作系统总共有32根地址线,每个地址能模拟的数字为0/1,所以最小就是0x00000000,最大就是0xFFFFFFFF。 64位同理。
5、页表
  • 1、图解
    在这里插入图片描述

  • 2、映射关系:
    虚拟地址空间分成一页一页
    物理地址分成一块一块
    使用页表将页和块映射起来
    在这里插入图片描述

扩展
  • 如何通过虚拟地址+页表的方式找到具体的物理地址

    • 虚拟地址 = 页号 + 页内偏移
    • 页号 = 虚拟地址 / 页的大小(4096(4kb))
    • 页内偏移 = 虚拟地址 % 页的大小
  • 为什么内存分配的时候,不采用连续分配的方式,而是一页一页离散分配的方式

    • 防止内存碎片,使小空间也可以被利用起来。
      在这里插入图片描述
  • fork创建子进程的时候,会不会拷贝页表?

    • 会,每个进程都有自己的页表,子进程最初的页表映射的内容就是来自于父进程。
  • 分段式:

    • 虚拟地址 = 段号 + 段内偏移
    • 段表 段号 :段的起始地址
      在这里插入图片描述
  • 段页式:

    • 虚拟地址 = 段号 + 页号 + 页内偏移
    • 段表 —> 段号:页表的起始位置
    • 页表 —> 页号:块号
      在这里插入图片描述

1、3、10 扩展问题

  • task_struct结构体代码
    之后的学习离不开task_struct结构体,例如文件描述符,进程信号,多线程等等的学习。

1、3、11 进程优先级问题

  • PRI:进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小,进程的优先级别越高,反之
  • 那NI呢?就是我们所说的nice值了,其表示进程可被执行的优先级的修正数值。
    这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级别变高,则其越快被执行,
    所以,调整进程优先级,在Linux下,就是调整进程的nice值,
    nice:取值范围是-20~19,一共40个级别。
  • 用top命令更改已存在进程的nice:(root用户进行修改)
top
 ->进入top后按“r”
 ->输入进程的PID
 ->输入nice值

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值