[Linux 进程(三)] 进程优先级,进程间切换,main函数参数,环境变量 ...

打印 上一主题 下一主题

主题 916|帖子 916|积分 2748


  
   
  1、进程优先级

  列队的本质就是确认优先级。
优先级是什么?它也是PCB中的一个整型字段数值越小,优先级越高。是得到某种资源的先后次序。
Linux进程的优先级数值范围:60~99。
Linux中默认进程的优先级都是80。

为什么要有优先级?本质是资源不敷。
谈到优先级,就不得不说我们以前学的权限,它两区别是什么呢?
权限是能不能得到某种资源。优先级是包管能申请到某种资源,只不过需要等一等。就如现实中,我们去吃饭,人很多,但是做饭师傅只有那么几个,看到能给你做好端上来,只不过是有次序的,考究先来后到。
Linux下进程的优先级概念:
  

  • cpu资源分配的先后次序,就是指进程的优先权(priority)。
  • 优先权高的进程有优先实行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
  • 还可以把进程运行到指定的CPU上,如许一来,把不重要的进程安排到某个CPU,可以大大改善系统团体性能。
  1.1 Linux下查看进程优先级

  首先我们先写一份C语言代码:
  1. #include <stdio.h>
  2. #include <unistd.h>
  3. int main()
  4. {
  5.     while(1)
  6.     {
  7.         printf("I am process, pid: %d\n", getpid());
  8.         sleep(1);
  9.     }
  10.    
  11.         return 0;
  12. }
复制代码
编译运行,我们查看一下该进程的优先级
  1. ps -la
复制代码

  Linux下进程的优先级是由两部门组成的:PRI(priority) + NI(nice)
那么优先级可不可以改呢? 可以,下面我们就学习一下怎么改。
  1.2 Linux 进程优先级的修改

  修改进程的优先级,并不是直接修改 PRI 而是修改NI值,从而到达修改PRI值的。
  PRI and NI

  

  • PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是步伐被CPU实行的先后次序,此值越小进程的优先级别越高。
  • 那NI呢?就是我们所要说的nice值了,其表现进程可被实行的优先级的修正数。
  这里修改PRI值的公式:PRI(new) = PRI(old) + nice
  top命令配合操作更改优先级

  输入top命令 -> 输入r -> 输入PID -> 输入nice值 就完成了进程优先级的修改,我们来试一下:
我们输入top后回车,来到此界面,再输入r后就提示我们输入PID

  接下来我们输入PID:

  输入完PID,它提示我们输入nice值,我们输入10:

  完成后,按q退出。
我们来查看一下13312进程的优先级有没有被改:

  我们可以看到进程的优先级已经被改,并且nice值确实也变了。修改后PRI值变大了,意味着进程优先级次序变小了。
我们在此基础上来修改一下nice值,这次我们输入-10,看看优先级会怎样变革:

这里表现将PID为13312的进程nice值设置成-10是不被允许的操作,这是怎么回事?
进程的优先级修改时,如果我们只是将优先级调小,普通用户身份就可以完成。但是如果我们想要调大,就需要以管理员身份/普通用户身份提权来操作,因此我们 top前加sudo 来操作。


这下确实能修改了,但是我们是在之前的基础上修改的呀,为什么nice值改为-10后,PRI值却是70呢?
因为每次修改PRI值的时候,PRI(old)值都是以80为基础,加上设置的nice值,得出的数值再赋给PRI(new)的。
我们再来试试,直接将nice设置为100,再看看PRI值会被改为多少。


这里我们发现,nice值并不是-100,而是-20,这又是为什么呢?
因为我们优先级最高是60,不管我们怎么去调整,最高60就限定了nice最小只能到-20,只要我们输入的nice值小于等于-20,都会被当-20来处置惩罚。
那么PRI的值最大是99,由此我们可以推测出,nice值最大被限定在19了,输入nice值大于等于19,都会被当作19来处置惩罚。

我们来测试一下:


确实不出我们所料呀。
我们看到有疑惑,为什么要把优先级限定在肯定的范围内呢?
os调理的时候,要做到公平,较为均衡的让每一个进程都要得到调理。因为优先级可以改,用户恶意让自己的进程不断在最前面实行,那么轻易导致优先级较低的进程,长时间得不到CPU资源,导致进程饥饿。
总结:
  

  • PRI值越小越快被实行,那么加入nice值后,将会使得PRI变为: PRI(new)=PRI(old)+nice。
  • 如许,当nice值为负值的时候,那么该步伐将会优先级值将变小,即其优先级会变高,则其越快被实行。
  • 所以,调整进程优先级,在Linux下,就是调整进程nice值。
  • nice其取值范围是-20至19,一共40个级别。
  • 需要夸大一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变革。
  • 可以理解nice值是进程优先级的修正修正数据。
  1.3 竞争 独立 并行 并发

  

  • 竞争性: 系统进程数目众多,而CPU资源只有少量,乃至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更公道竞争相干资源,便具有了优先级。
  • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
  • 并行: 多个进程在多个CPU下分别,同时举行运行,这称之为并行。
  • 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。
  调整系统优先级有很多方法,这里我们只说了这一种方式,我们学习了本质,有了底层的打底,操作再去学习就会变的简单了,并且轻易我们是不需要去改优先级的。
  2、进程间切换

  我们要知道,一个进程并不是占据CPU就一直运行,每隔一段时间,自动被从CPU上剥离下来,所以这就会存在进程切换的过程。
Linux内核支持进程之间举行CPU资源抢占的。
如果一个进程的PRI值是80,它正在CPU上运行,但是又来一个进程,它的PRI是60,意味着它需要被运行,这时就把PRI为80的进程拿下来,先让PRI为60的进程跑,可能此时时间还没到。
所以Linux调理的原则全程:基于时间片的轮转式抢占式内核。
CPU运行的时间特别快,我们感知不到,在一段时间内,进程是高速的的不断的切换,我们所感知到的进程是并发的。
标题: 进程切换的时候,可能一份代码并没有跑完,但是需要切换别的一个进程了,那下一次再运行此进程的时候,CPU怎么知道是从哪开始呢?
CPU中有寄存器,eip就是专门记录步伐运行到哪一行的。
由此,我们也可以知道,一个CPU虽然只有一套寄存器硬件,但是寄存器的数据不光仅是一套。寄存器 != 寄存器内容。并且进程切换后,进程的数据存在CPU的寄存器中。

标题: CPU内的寄存器数据生存在哪呢?
CPU内的寄存器数据生存在进程PCB中(简单理解),本质:CPU寄存器的内容,生存在内存中。
生存完之后,寄存器中的数据不会清空,下个进程被调理运行时,直接覆盖即可。


  3、Linux2.6内核进程调理队列

  这部门是选学,读者看自己环境来决定。
下图就是CPU维护的运行队列我们重要盯着蓝色框和赤色框来看

  3.1 活跃进程

  首先,我们要知道,Linux下进程优先级范围为60~99共计40个等级,其次,运行队列是分活跃队列和逾期队列,他们两个的功能后面我们就知道了。

  CPU在运行时,会从上到下去扫描队列,优先级为n的位置不为空就会去运行它指向的PCB,为空就今后走,去找不为空的位置,直到遍历完队列。
  3.2 逾期进程

  标题: 如果CPU正在运行队列中,运行优先级为99的进程,而现在一个优先级为70的进程加载进来,会直接放入活跃进程队列中,与正在运行的队列抢占资源吗?
肯定是不会的,如果我们不断加载进来进程,原本优先级低的进程,迟迟得不到CPU资源,导致进程饥饿!
所以新加载进来的进程,会先去逾期进程数组按照优先级次序列队。


在活跃进程数组没有被全部运行完时,CPU不会去调理逾期进程的数组,这就包管了公平性。
当活跃队列的进程全部运行完后,CPU不是去逾期进程数组调理,而是swap(active, expired),改变指向后,依然运行活跃进程数组。

由此我们也就知道,在进程间切换的时候,我们就是把换出的进程放入了逾期进程的数组中,等待CPU下一次的调理。
  4 main函数参数 — 命令行参数

  main函数是有两个参数的,int argc,char* argv[]。
我们来介绍一下:
  1. int main(int argc, char* argv[]);
  2. // 这两个参数叫做命令行参数
  3. // argv是一个数组,类型是char*,也就是指针数组
  4. // argc表示这个数组的元素个数
复制代码
我们现在还不知道这个数组中存放的是什么内容,我们在Linux下写一个main函数,打印一下数组内容看看:
  1. #include <stdio.h>
  2. int main(int argc, char* argv[])
  3. {
  4.         int i = 0;
  5.     for( ; i < argc; i++)
  6.     {
  7.         printf("argv[%d]: %s\n", i, argv[i]);
  8.     }
  9.    
  10.         return 0;
  11. }
复制代码

我们发现,它把我们的命令打印出来了,我们多写点看看怎样。

这里原来是把我们的命令以空格分割开,存入到字符串指针数组中的!

  标题: 那是谁把命令放入到数组中的?
将命令行输入的字符串放入数组是os干的。
  4.1 使用main函数的参数实现一个计算器

  既然main函数可以拿到命令行输入的字符串,那我们可以用其写出一个简易的计算器,代码如下:
  1. #include <stdio.h>                                                                                                              
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main(int argc, char* argv[]) // argc代表参数个数,argv是字符串数组参数
  5. {
  6.     // 简易版计算器
  7.     if(argc != 4)
  8.     {
  9.         printf("Use Error!\nUsage %s op[-add|-sub|-mul|-div] d1 d2\n", argv[0]);
  10.         return 0;
  11.     }
  12.     // 将字符数字转为
  13.     int x = atoi(argv[2]);
  14.     int y = atoi(argv[3]);
  15.     int result = 0;
  16.     // 你的程序一定有4个命令行参数,第一个是程序名
  17.     if(strcmp("-add", argv[1]) == 0)
  18.     {
  19.         result = x + y;
  20.         printf("%d + %d = %d\n", x, y, result);
  21.     }
  22.     else if(strcmp("-sub", argv[1]) == 0)
  23.     {
  24.         result = x - y;
  25.                 printf("%d - %d = %d\n", x, y, result);
  26.     }
  27.     else if(strcmp("-mul", argv[1]) == 0)
  28.     {                                                                                                                           
  29.         result = x * y;
  30.         printf("%d * %d = %d\n", x, y, result);
  31.     }
  32.     else if(strcmp("-div", argv[1]) == 0)
  33.     {
  34.         if(y == 0) printf("%d / %d = error! div zero\n", x, y);
  35.         else
  36.         {
  37.             result = x / y;
  38.             printf("%d / %d = %d\n", x, y, result);
  39.    
  40.         }
  41.     }
  42.     else
  43.     {
  44.         printf("Use Error!\nThe second parameter should is [-add|-sub|-mul|-div] !\n");
  45.         return 0;
  46.     }
  47.     return 0;
  48. }
复制代码
使用方法:
1、先输入可实行步伐;
2、第二个字符串输入 -add/-sub/-mul/-div;
3、第三个,第四个输入操作数;

  4.2 模仿实现touch命令

  在使用完我们写的计算器后,有没有感觉到,跟我们的Linux下指令很雷同。
比如:ls命令,我们可以配选项:ls -l -a。
这些指令就是用C语言写的,加上一些选项在表现器上表现差别效果,它们的本质不就是用到了命令行参数么。
下面我们自己在实现一份touch指令代码:
  1. #include <stdio.h>
  2. int main(int argc, char* argv[])
  3. {
  4.     if(argc != 2) // 输入的字符串不规范
  5.     {
  6.         printf("touch missing file operand!\n");
  7.         return 1;
  8.     }
  9.     FILE* fp = fopen(argv[1], "w"); // 以"w"方式打开,当文件不存在时,会自动创建                                                
  10.     if(fp != NULL)                                          
  11.         fclose(fp);                                         
  12.                                                             
  13.     return 0;                                               
  14. }        
复制代码
我们使用自己写的touch来创建文件试一下:

  5、环境变量

  系统中有很多的环境变量,我们可以使用 env 命令来查看一下:

其他我们不知道,今天我们挑着来学几个。
  5.1 PATH的熟悉

  我们命令行参数算是学明白了,但是各人有没有想过如许几个标题。
标题:
  

  • 为什么我们写出来的步伐在实行的时候需要加 ./
  • 为什么在实行系统的指令的时候不需要加 ./
  实行一个步伐的前提是先找到这个可实行步伐我们写的步伐在实行的时候,加上 ./ 本质是告诉bash在当前目录下找该步伐。
系统指令也是 C/C++ 写出来的步伐,那为什么系统指令不需要加呢?
一样平常的系统指令我们可以直接用,也可以加上它的路径实行:

这里系统指令不用加 ./ 就得提一下一个概念了:环境变量。
记录系统当中默认搜索路径的环境变量叫做:PATH(一样平常环境变量名是全大写的)。
在实行系统指令时,系统会去PATH中找当前的可实行步伐在不在这些路径中,如果在正常实行,不在就报错。
查看环境变量内容指令:
  1. echo $xxx  // 例如查看PATH,echo $PATH
复制代码

  这些路径按 : 分割开
先在/usr/local/bin找,没有去下一个路径找,找到实行,没找到继续下一个,找完都没有就返回错误信息。
因为我们自己的可实行步伐并不在这些路径中,所以我们的可实行步伐在实行的时候需要加上 ./ 来实行。
  5.2 修改环境变量PATH

  想要我们自己的步伐像系统指令一样运行,我们可以将可实行步伐的路径追加到环境变量PATH中去!
命令如下:
  1. PATH = $PATH:要添加的路径
复制代码
注意: 这里不能直接等于要添加的路径,直接等于就会覆盖掉原本的PATH,因为我们要按照上面追加的形式的来写。

此时,我们再去运行我们自己的mytouch步伐就不用再带 ./ 了。我们来试试:

注意: 默认更改环境变量,只限于本次登录,重新登陆,环境变量自动被规复。想要一劳永逸,可以将自己的可实行步伐放入到默认的路径中这个过程就做步伐安装)。
  5.3 HOME的熟悉

  标题: 各人有没有疑惑过,我们在登录xshell的时候,我们以差别身份登录,进入的是差别的目录呢 ?

标题:
  

  • 凭什么普通用户,登录后默认所处的目录是/home/XXX ?
  • 凭什么root,登录后默认所处的目录是/root ?
  因为系统中有一个环境变量HOME,在我们输入用户名与密码的时候,辨认出登录者身份,初始化HOME,它能辨认出登录者是普通用户还是root,并完成正确的初始化。

系统在登录的末了一刻,cd HOME所记录的路径,因此就实现了差别身份,进入差别的目录。
总结:
1、输入用户名 && 密码;
2、认证;
3、形成环境变量(不止一个);
 3.1 根据用户名,初始化                                              H                               O                               M                               E                               =                               /                               r                               o                               o                               t                               ,                                      HOME=/root,                        HOME=/root,HOME=/home/XXX
4、末了,cd $HOME。

  5.4 怎样获取环境变量

  我们知道了环境变量,以及查看环境变量命令,加之对HOME这个环境变量的学习后
我们明白了,系统中会存在大量的环境变量,每一个环境变量都有自己的特殊用途,用来完成特定的系统功能!
标题: 那么怎样获取环境变量呢?
我们这里讲一个函数,getenv(),并配合一个场景来讲。

  这里讲了,getenv()函数是以变量名来查找的,返回相应的字符串指针。
我们是不是可以按照用户名来对用户做甄别,差别用户去实行差别的代码。
假如,我们写一段代码,只想让root来实行,普通用户不能实行:
  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main()
  5. {
  6.         char* user = getenv("USER"); // 获取环境变量USER的内容
  7.         if(strcmp(user, "root") == 0)
  8.     {
  9.         printf("myself command!\n");
  10.     }
  11.     else
  12.     {
  13.         printf("%s是一个非法用户!\n", user);
  14.     }
  15.    
  16.         return 0;
  17. }
复制代码
编译后我们以普通用户身份运行:

我们再切换到root身份运行:
在这里插入代码片

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! 更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

道家人

金牌会员
这个人很懒什么都没写!

标签云

快速回复 返回顶部 返回列表