【Linux】进程的优先级&&情况变量

打印 上一主题 下一主题

主题 522|帖子 522|积分 1566

个人主页 : zxctscl
如有转载请先通知
  
  
1. 媒介

上一篇在进程中提到了 【Linux】进程状态&&僵尸进程和孤儿进程&&壅闭、挂起和运行,这次来继承来谈进程。
2. 进程的优先级

2.1 什么是优先级

在进程的PCB中存在一个进程的优先级,那么什么是进程的优先级?
进程的优先级就是指定一个进程获取某种资源的顺序。
进程中利用task_struct进程控制块结构体中的内部字段用一个整型prio表示优先级。
Linux中优先级数字越小,优先级越高。
比较一下优先级和权限:权限决定一件事能不能做,而有优先级就表示一件变乱能做只是代表获取资源的顺序。
2.2 为什么要有优先级

因为进程访问的资源(CPU)时有限的,系统中进程大部分情况都是有较多的。
就像打游戏时间,键盘、鼠标等硬件只有一套,不同的进程本质上对系统硬件资源原来就是通过操纵系统方式来实现资源的共享。
更形象就像在下课高峰期,食堂买饭要排队。
操纵系统关于调理和优先级的原则:分时操纵系统,要保证基本的公平。如果进程因为长时间不被调理,就造成了饥饿问题。
2.3 优先级的查看方式

为了方便查看,先用C语言写测试代码:
Makefile:
  1.   1 myprocess:myprocess.c
  2.   2   gcc -o $@ $^
  3.   3 .PHONY:clean
  4.   4 clean:
  5.   5   rm -f myprocess
复制代码
myprocess.c:
  1.   1 #include<stdio.h>
  2.   2 #include<unistd.h>
  3.   3
  4.   4 int main()
  5.   5 {
  6.   6   while(1)
  7.   7   {
  8.   8     printf("I am a process,pid:%d\n",getpid());
  9.   9     sleep(1);
  10. 10   }
  11. 11 }
复制代码
在Linux中查看优先级的方式用到命令:
  1. ps -al
复制代码

PRI:进程的优先级
NI:进程优先级的修正数据,N是nice值。新的优先级=优先级+nice值,达到对于进程优先级动态修改的过程。
UID : 代表执行者的身份
PID : 代表这个进程的代号
PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
2.4 对优先级调整

改之前的NI:

想要对进程优先级调整就想要用到命令:
  1. top
复制代码

然后输入:r

再输入进程的pid:

最后输入要修改的nice值:
先修改为100:

再来查看一下这个进程的NI:

以是说:nice值不能让用户任意调整,而是有范围的,如果随便写就有可能使操纵系统调理出现不均衡,必须在可控范围内调整。
nice其取值范围是-20至19,一共40个级别。

当再想要修改nice值的时间,就不能修改了,平凡用户不能频仍修改nice值,把账号先切换为root,再把nice值修改为-10:
此时PRI就变为了70:

每次调整优先级PRI都是从80开始范围是从60到99
新的优先级=优先级+nice值
一样寻常不推荐用户调整进程的优先级

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

在C语言中会出现main函数带参的情况。
像:
  1. int main(int argc,char *argv[])
  2. {}
复制代码
main函数的参数可以带可不带。
这些参数
在Linux内里写一个测试代码:
  1.   1 #include<stdio.h>
  2.   2 #include<unistd.h>
  3.   3
  4.   4 int main(int argc,char *argv[])
  5.   5 {
  6.   6   int i;
  7.   7   for(i=0;i<argc;i++)
  8.   8   {
  9.   9     printf("argv[%d]->%s\n",i,argv[i]);
  10. 10   }
  11. 11 }
复制代码
argc表示数组中元素的个数,argv[]是一个指针数组。
如果直接执行程序不带参数,那么默认argv[0]执行的就是执行的程序,而且就是有它一个。
如果带1参数,会自动在将参数酿成2个,0号下标指向执行的程序,1号下标就只向这个参数。

这就是命令行字符串。

这里的argv是一个酿成数组,把命令行字符串以空格为分隔符放在argv内里,下标与输入顺序匹配。再将这些以参数的情势传给了main函数,有几个这样的字符串,那么argc就是几。argv数组最后必须以NULL末了。

修改一下代码:
  1.   1 #include<stdio.h>
  2.   2 #include<unistd.h>
  3.   3 #include<string.h>
  4.   4
  5.   5 int main(int argc,char *argv[])
  6.   6 {
  7.   7   if(argc!=2)
  8.   8   {
  9.   9     printf("Usage: %s -[a,b,c,d]\n",argv[0]);
  10. 10     return 1;
  11. 11   }
  12. 12
  13. 13   if(strcmp(argv[1],"-a")==0)
  14. 14   {
  15. 15     printf("this is function1\n");
  16. 16   }
  17. 17
  18. 18   else if(strcmp(argv[2],"-b")==0)
  19. 19   {
  20. 20     printf("this is function2\n");
  21. 21   }
  22. 22
  23. 23   else if(strcmp(argv[3],"-c")==0)
  24. 24   {
  25. 25     printf("this is function3\n");
  26. 26   }
  27. 27
  28. 28   else if(strcmp(argv[4],"-d")==0)
  29. 29   {
  30. 30     printf("this is function4\n");
  31. 31   }
  32. 32   else{
  33. 33   printf("no this function\n");
  34. 34   }
  35. 35 }
  36. 36
复制代码
编译运行一下,发现必须要带选项,那就带上:

同一个程序可以通过不同的选项来执行同一个程序内的不同的功能。
就像是ls带不同选项,功能不一样:

命令行参数本质交给我们程序的不同选项,用来定制不同的程序功能。命令中就会携带许多的选项。

写一个父子进程的代码:
  1.   1 #include<stdio.h>
  2.   2 #include<unistd.h>
  3.   3 #include<string.h>
  4.   4
  5.   5 int g_val=100000;
  6.   6
  7.   7 int main()
  8.   8 {
  9.   9   printf("I am a father process,pid:%d,ppid:%d,g_val:%d\n",getpid(),getppid(),g_val);
  10. 10   sleep(5);
  11. 11
  12. 12   pid_t id=fork();
  13. 13   if(id==0)
  14. 14   {
  15. 15     while(1)
  16. 16     {
  17. 17      printf("I am a child process,pid:%d,ppid:%d,g_val:%d\n",getpid(),getppid(),g_val);
  18. 18      sleep(1);
  19. 19
  20. 20     }
  21. 21   }
  22. 22   else
  23. 23   {
  24. 24   while(1)
  25. 25   {
  26. 26   printf("I am a father process,pid:%d,ppid:%d,g_val:%d\n",getpid(),getppid(),g_val);
  27. 27   sleep(1);
  28. 28
  29. 29   }
  30. 30 }
  31. 31 }
复制代码
编译运行:

发现父进程的数据,默认能被子进程看到并访问。
父进程的ppid是谁的?
再修改一下代码:把创建子进程的代码解释

再编译运行一下:
发现这个ppid照旧24361

查看一下:
发现它是bash

当把代码改回之前的:

然后重新编译运行:发现ppid照旧24361,照旧bash:

说明命令行中启动的程序,都会酿成进程,其实都是bash的子进程。输入的命令行字符串,默认是输入给父进程bash的。
就像ls,本身也是一个可执行程序,启动它就和启动本身写的程序是一样的

4. 情况变量

4.1 情况变量与配置文件

4.1.1 情况变量开端介绍

为什么执行本身写的程序时间要带路径:

而ls就不必要:

也可以带路径执行:

这个主要是因为在Linux系统中,存在一些全局的设置,表明,告诉命令行解释器,应该去哪些路径下去探求可执行程序。
这些设置在PATH内里保存,查看的话就用:
  1. echo $PATH
复制代码

系统中许多配置,在我们登录Linux系统的时间,就已经被加载到bash进程中,而bash进程就在内存中。
PATH:情况变量
要打印情况变量的内容用:$PATH
bash在执行命令的时间,想要先找到命令,因为未来要加载。
命令会在对应的路径下找,如果没有找到就报:

如果找到了就会加载并运行这个程序:


如果不加路径来执行myprocess会报:找不到

如果必要把本身写的程序执行和系统的一样,可以可执行程序添加到bash路径下:

但是一些命令就不能了,PATH内里就只剩下刚才加的路径:

因为对情况变量直接赋值,就相称于把情况变量直接覆盖了
本身写的程序到是可以直接运行了:

直接重新登录就可以了:
此时路径又返来了,刚才设置的情况变量就没有了

默认我们查到的情况变量是内存级的。
不用覆盖,怎么添加情况变量:
用:
  1. PATH=$PATH:路径
复制代码

此时再查看情况变量时间:这个情况变量就有了

再执行程序的时间带不带路径都可以:

4.1.2 配置文件

最开始的情况变量不是在内存中,而是在系统对应的配置文件中,用户在登录时间,会创建一个bash进程,此时bash就会读取配置文件,就会把配置文件内里的情况变量在bash内里拷贝一份。
这就是为什么重新登岸的时间之前在PATH加到就不存在了,因为配置文件没有改。
这个配置文件在哪里呢?
切换到家目录下,有与配置文件有关的文件:.bash_profile、.bashrc另有/etc/bashrc

打开.bash_profile:

情况变量默认是在配置文件内里的。
打开.bash_profile后把路径加上去:

此时不加路径也可以运行:

程序登岸:不加路径照旧可以运行

4.2 更多情况变量

用env可以查看其他情况变量

来看看PWD:
会随着路径变化,把当前路径会记录在PWD的情况变量中:

系统启动的时间会把改程序的shell运行起来,这就有了命令行解释器:

曾经输入的命令是记录下来的,不可能全部都记住,HISTSIZE默认记录新的3000条汗青命令

用history可以查看汗青命令:

是目前维护汗青命令的数量:

这些情况变量是在用户登岸的时间系统自动加载的:


我们可以本身导入情况变量:
  1. export THIS_IS_MY_ENV=value
复制代码

此时就存在了这个情况变量:

取消情况变量:
  1. unset THIS_IS_MY_ENV
复制代码
此时就查不到了:


当加情况变量时间不加export,直接写,不会报错:
也可以查出来

这种变量叫做本地变量。
4.3 团体明白情况变量与系统

先来写一个获取情况变量的测试代码:
  1.   1 #include<stdio.h>
  2.   2 #include<unistd.h>
  3.   3 #include<string.h>
  4.   4
  5.   5
  6.   6 int main()
  7.   7 {
  8.   8   extern char** environ;
  9.   9   int i;
  10. 10   for(i=0;environ[i];i++)
  11. 11   {
  12. 12     printf("env[%d]->%s\n",i,environ[i]);
  13. 13   }
  14. 14 }
复制代码

这些情况变量就是和用env指令查到的一样。
情况变量默认也是可以被子进程拿到的,就说明本身不在子进程内里,而情况变量们默认是在bash内部。
解释一下代码:

在磁盘中:有系统级的配置文件,有全局的也有当进步程的,还包含了情况变量。
在内存中:当有一天我们登岸时,就会在内存中给当前用户创建一个进程,就是bash/shell,登岸的时间把这些配置文件信息就加载到bash内部。
所有情况变量的数据都在bash内里。
情况变量有变量名有变量内容,情况变量的本质就是数据。当启动我们本身的程序时,就会在内存中创建一个子进程./myprocess,而父进程的数据,默认能被子进程看到并访问,情况变量是全局的。
情况变量如此多,那么在bash内部怎样构造情况变量?
实际上bash在启动的时间,会维护一张表,这张表是一个指针数组char *env[],指向内容全是char*的。每当有一个情况变量,像PATH=/usr/bin:a/b/c…,也就是字符串,情况变量就可以把对应的字符串从配置文件加载过来,配置信息就有了。把情况变量的地址填到情况变量表内里,这个情况变量就纳入到了bash内里。每一个情况变量都是字符串等于内容,最后在以NULL末了。
bash进程在启动的时间,默认会给我子进程的两张表:argv[]命令行参数表,env[]情况变量表。bash通过各种方式交给子进程。argv[]命令行参数表来自用户输入的命令行;env[]情况变量表从配置文件来。
系统为了方便用户找到情况变量表, 就提供了extern char **environ指针就能被全局看到。就可以用[]来访问指针字符串的内容。


还可以在main函数内里加三个参数来获取情况变量:
  1.     1 #include<stdio.h>
  2.     2 #include<unistd.h>
  3.     3 #include<string.h>
  4.     4
  5.     5
  6.     6 int main(int argc,char *argv[],char *env[])
  7.     7 {
  8.     8   int i;
  9.     9   for(i=0;env[i];i++)
  10.    10   {
  11.    11     printf("env[%d]->%s\n",i,env[i]);
  12.    12   }
  13.    13 }
复制代码
编译运行:


exoprt导情况变量本质上就是在env[]情况变量表中找到一个没有被利用的位置,然后把它指向对应的情况变量。导情况变量就是把字符串添加到表里。
4.4 情况变量的特性

情况变量具有系统级的全局属性,因为情况变量本身会被子进程继承
系统刚开始启动时间,启动了bash,bash可以启动许多进程,进程可以继承通过代码创建子进程。但是不管有多少给子进程,bash都能拿到所有子进程对应的情况变量,也就是情况变量具有系统级的全局属性。
系统中还存在getenv,可以根据情况变量直接拿到情况变量的内容,可以单个获取情况变量的内容。

putenv就是用来导情况变量

用代码来获取一下:
  1.     1 #include<stdio.h>
  2.     2 #include<unistd.h>
  3.     3 #include<string.h>
  4.     4 #include<stdlib.h>
  5.     5
  6.     6 int main(int argc,char *argv[],char *env[])
  7.     7 {
  8.     8  char *path=getenv("PATH");
  9.     9  if(path==NULL)return 1;
  10.    10  printf("path:%s\n",path);
  11.    11 }
复制代码
编译运行之后,就可以单独获取PATH一个情况变量了:

获取情况变量的三种方式:

  • extern char **environ;
  • 通过main函数参数
  • getenv(“path”);

用export导的情况变量也会创建子进程吗?

并不是,export导的情况变量不会创建子进程。它是内建命令。
在Linux中百分之八十的美丽都是bash创建子进程执行的。另有一些命令是由bash本身亲自去执行的。bash也是用c语言写的,就相称于在bash内里有个export()函数,直接函数调用就执行export了。
把情况变量先清空:

再在执行其他命令,能被执行的都是内建命令

本地变量只在本bash内部有用,无法被子进程继承下去。导成情况变量,此时才能被获取。
有问题请指出,大家一起进步!!!

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

本帖子中包含更多资源

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

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

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

本版积分规则

前进之路

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

标签云

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