当前位置:   article > 正文

Linux:进程优先级与命令行参数

Linux:进程优先级与命令行参数

目录

1.进程优先级

1.1 基本概念

1.2 查看系统进程

1.3 修改进程优先级的命令

2.进程间切换

2.1 相关概念

2.2 Linux2.6内核进程调度队列(了解即可)

3.命令行参数


1.进程优先级

1.1 基本概念

  1. cpu资源分配的先后顺序,就是指进程的优先权(priority)。
  2. 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
  3. 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。 

我们知道进程在内存中是需要排队的,比如运行队列,等待队列。那排队是干什么的:就是在确认优先级,来确定得到某种资源的先后顺序。为什么要确认优先级,本质就是资源不足。那么操作系统是怎么做到呢?我们下面讲解:

优先级其实就是PCB中的一个 int 字段数值越小,优先级越大,跟我们的考试排名一样。Linux进程的优先级数值范围:60~99。Linux中默认进程的优先级都是80。

1.2 查看系统进程

我们先编写一段代码

在linux或者unix系统中,用ps -la 命令则会类似输出以下几个内容:

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

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值

PRI and NI:

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

那NI就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值

PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为PRI(new)=PRI(old)+nice。pri(old) ,都是从80开始的!

这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行所以,调整进程优先级,在Linux下,就是调整进程nice值

nice其取值范围是-20至19,一共40个级别。nice调整最小是:-20,超过部分统一当成-20。nice调整最大是:19,超过部分统一当成19。


PRI vs NI:

  • 需要强调一点的是,进程的nice值不是进程的优先级,他们不是一个概念,但是进程nice值会影响到进程的优先级变化。可以理解nice值是进程优先级的修正修正数据

1.3 修改进程优先级的命令

用top命令更改已存在进程的nice:

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

我们输入进程号讲 nice 改为19

普通用户是没有办法将优先级调大,让PRI减小的。需要使用su换成root,或使用sudo命令。 

2.进程间切换

2.1 相关概念

  • 竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高效完成任务,更合理竞争相关资源,便具有了优先级。
  • 独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰。
  • 并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行。
  • 并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发。

因为要并发,所以必定要考虑进程间切换。

每一个进程不是占有CPU就一直运行,每隔一段时间,会自动被操作系统从cpu上剥离下来。Linux内核是支持进程之间进行cpu资源抢占的!是基于时间片的轮转式抢占式内核。

为什么我们函数内定义的栈临时变量,会返回给外部,我们的程序/进程,它怎么知道我们当前运行到哪里里?如何做到函数间跳转? 因为cpu内存在大量寄存器,比如eip是程序计数器或者叫pc,会自动执行我们要执行的下一行代码。我们的进程在运行的时候,是会使用这些寄存器的,我们的进程,会产生各种数据,在寄存器中临时保存。

如果我们有多个进程呢?各个进程在CPU寄存器中形成的临时数据,都应该是不一样的!而cpu内寄存器只有一套,我们如何做到让每个进程使用cpu时能从上次时间片执行到的位置继续执行?我们可以先简单的理解为时间片结束后,cpu寄存器中的数据会先保存到进程PCB中,然后下次执行时先读取PCB中存储的寄存器的数据,然后继续执行,本质就是将CPU寄存器的内容,保存到内存中!

2.2 Linux2.6内核进程调度队列(了解即可)

上图是Linux2.6内核中进程队列的数据结构,之间关系也已经给大家画出来,方便大家理解

一个CPU拥有一个runqueue

  • 如果有多个CPU就要考虑进程个数的负载均衡问题

优先级

  • 普通优先级:100~139(我们都是普通的优先级,想想nice值的取值范围,可与之对应!)
  • 实时优先级:0~99(我们这里不关心)

活动队列

  • 时间片还没有结束的所有进程都按照优先级放在该队列
  • nr_active: 总共有多少个运行状态的进程
  • queue[140]: 一个元素就是一个进程队列,相同优先级的进程按照FIFO规则进行排队调度,所以,数组下标就是优先级!
  • 从该结构中,选择一个最合适的进程,过程是怎么的呢?

1. 从0下表开始遍历queue[140]
2. 找到第一个非空队列,该队列必定为优先级最高的队列
3. 拿到选中队列的第一个进程,开始运行,调度完成!
4. 遍历queue[140]时间复杂度是常数!但还是太低效了!

  • bitmap[5]:一共140个优先级,一共140个进程队列,为了提高查找非空队列的效率,就可以用 5*32 个比特位表示队列是否为空,即位段,这样,便可以大大提高查找效率!

过期队列

  • 过期队列和活动队列结构一模一样
  • 过期队列上放置的进程,都是时间片耗尽的进程,或者是刚到运行对列中的进程。
  • 当活动队列上的进程都被处理完毕之后,对过期队列的进程进行时间片重新计算

active指针和expired指针

  • active指针永远指向活动队列
  • expired指针永远指向过期队列
  • 可是活动队列上的进程会越来越少,过期队列上的进程会越来越多,因为进程时间片到期时一直都存在的。
  • 没关系,在合适的时候,只要能够交换active指针和expired指针的内容,就相当于有具有了一批新的活动进程!

总结

在系统当中查找一个最合适调度的进程的时间复杂度是一个常数,不随着进程增多而导致时间成本增加,我们称之为进程调度O(1)算法

3.命令行参数

 命令行参数是什么?

我们看下面一段代码看下面一段代码

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main(int argc, char *argv[])
  5. {
  6. int i = 0;
  7. for(;i<argc;i++)
  8. {
  9. printf("%d: %s\n",i, argv[i]);
  10. }
  11. printf("hello world\n");
  12. return 0;
  13. }

运行输出: 

可以发现main函数是可以传参的,shell 会自动讲命令行输入的一大串字符,按空格分割成小的字串,第一参数argc存命令行字串个数,第二个参数argc是一个指针数组存字串内容。

命令行参数,可以支持各种指令级别的命令行选项的设置!这样就可以理解之前学的指令,选项是什么关系了。

我们来模拟实现一个计算器

  1. #include <stdio.h>
  2. #include <string.h>
  3. #include <stdlib.h>
  4. int main(int argc, char *argv[])
  5. {
  6. if(argc != 4)
  7. {
  8. printf("Use error\nUsage: %s op[-add|sub|mul|div] d1 d2\n",argv[0]);
  9. return 1;
  10. }
  11. // 你的程序一定有4个命令行参数,第一个是程序名
  12. int x = atoi(argv[2]);
  13. int y = atoi(argv[3]);
  14. if(strcmp(argv[1],"-add")==0)
  15. {
  16. int result = x+y;
  17. printf("%d+%d=%d\n",x,y,result);
  18. }
  19. else if(strcmp(argv[1],"-sub")==0)
  20. {
  21. int result = x-y;
  22. printf("%d-%d=%d\n",x,y,result);
  23. }
  24. else if(strcmp(argv[1],"-mul")==0)
  25. {
  26. int result = x*y;
  27. printf("%d*%d=%d\n",x,y,result);
  28. }
  29. else if(strcmp(argv[1],"-div")==0)
  30. {
  31. if(0==y)
  32. {
  33. printf("%d/%d=error! div zero\n",x,y);
  34. }
  35. else
  36. {
  37. int result = x/y;
  38. printf("%d/%d=%d\n",x,y,result);
  39. }
  40. }
  41. else
  42. {
  43. printf("Use error,you should use the right command line\nUsage: %s op[-add|sub|mul|div] d1 d2\n",argv[0]);
  44. }
  45. return 0;
  46. }

 运行结果:

对于为什么系统命令不用加 ./指定位置 ,而我们写的程序就需要写 ./ ,这就涉及到环境变量了,下一篇文章我们讲解环境变量。

本篇结束!

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/我家小花儿/article/detail/627428
推荐阅读
相关标签
  

闽ICP备14008679号