【Linux】进程优先级 && 命令行参数 && 环境变量

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

目录

文章目录

前言

一、进程优先级

1.1、进程优先级的基本概念

1.2、优先级 VS 权限

1.3、为什么要有优先级?

1.4、Linux的优先级的特点 && 查看方式

1.5、PRI and NI

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

1.7、其他概念

二、命令行参数

三、环境变量

3.1、基本概念

3.2、常见环境变量

3.3、查看环境变量方法

3.4、有什么方法可以不用带路径,直接就可以运行呢?

强硬的方法:

温柔的方法:

但是我们依然想要将可执行程序myprocess的路径添加到PATH环境变量里?

我们想要我们添加的路径,永久的保存在PATH环境变量里,怎么做呢?

3.5、和环境变量相关的命令

3.6、环境变量的组织方式

3.7、通过代码如何获取环境变量

通过第三方变量environ获取

命令行第三个参数

3.8、通过系统调用获取或设置环境变量

3.9、环境变量通常是具有全局属性的

3.10、内建命令

总结



前言

世上有两种耀眼的光芒,一种是正在升起的太阳,一种是正在努力学习编程的你!一个爱学编程的人。各位看官,我衷心的希望这篇博客能对你们有所帮助,同时也希望各位看官能对我的文章给与点评,希望我们能够携手共同促进进步,在编程的道路上越走越远!


提示:以下是本篇文章正文内容,下面案例可供参考

一、进程优先级

1.1、进程优先级的基本概念

  • 指定进程获取某种资源(如:CPU等)的先后顺序。
  • 优先权高的进程有优先执行权利。配置进程优先权对多任务环境的linux很有用,可以改善系统性能。
  • 还可以把进程运行到指定的CPU上,这样一来,把不重要的进程安排到某个CPU,可以大大改善系统整体性能。
  • Linux中优先级数字越小,优先级越高。

要维护一个进程的优先级:task_struct 进程控制块(是描述进程,里面包含了进程的所有属性) --->     struct ----> 内部字段 ----> (default_proi = 80) + (nice = ??) = proi(新的优先级)。

进程的优先级也是进程控制块中所有属性的一种(是内部字段中的一部分)。

1.2、优先级 VS 权限

权限:是能不能的问题。

优先级:已经能了,我们获取资源的顺序。

1.3、为什么要有优先级?

进程访问的资源(CPU)始终都是有限的,系统中进程大部分情况都是较多的。

操作系统关于调度和优先级的原则:分时操作系统,基本的公平,如果进程因为长时间不被调度,就造成了饥饿问题。

1.4、Linux的优先级的特点 && 查看方式

  • ps -l:只能查看当前终端(当前所在分频页面)下启动的进程。
  • ps -al:查看所有终端下启动的进程。

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

  • UID : 代表执行者的身份
  • PID : 代表这个进程的代号
  • PPID :代表这个进程是由哪个进程发展衍生而来的,亦即父进程的代号
  • PRI :代表这个进程可被执行的优先级,其值越小越早被执行
  • NI :代表这个进程的nice值
  • 每次调整优先级,都是从80开始的
  • nice/renice:可以对一个指定的进程,在启动前或运行时,对进程的优先级做动态调整
  • nice并不能让你任意调整,而是有范围的!若任意调整的话,会打破原则中基本的公平
  •  一个进程的优先级是不能频繁更改的

NI:进程优先级的修正数据,nice值,新的优先级 = 优先级 + nice,达到对于进程优先级动态修改的过程。

nice并不能让你随意调整,而是有范围的。[-20~19]

1.5、PRI and NI

  • PRI也还是比较好理解的,即进程的优先级,或者通俗点说就是程序被CPU执行的先后顺序,此值越小 进程的优先级别越高
  • 那NI呢?就是我们所要说的nice值了,其表示进程可被执行的优先级的修正数值
  • PRI值越小越快被执行,那么加入nice值后,将会使得PRI变为:PRI(new)=PRI(old)+nice
  • 这样,当nice值为负值的时候,那么该程序将会优先级值将变小,即其优先级会变高,则其越快被执行
  • 所以,调整进程优先级,在Linux下,就是调整进程nice值
  • nice其取值范围是-20至19,一共40个级别。

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

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

1.7、其他概念

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

多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进的方式:
如果这种方式下,进程过多,CPU切换负担过重,那么这些进程会出现卡顿的情况,本质是每一个进程被CPU调度的周期变长了。

二、命令行参数

vim Makefile
myprocess : myprocess.c
     gcc - o $@ $ ^ -g
.PHONY:clean
clean :
     rm - f myprocess
		 

:%s/testStatus/myprocess/   //:将testStatus改成myprocess
vim myprocess.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

//第一个参数argc代表指针数组中参数的个数有多少  
//第二个参数类型:指针数组,char *指向的是字符串首字符的地址
int main(int argc, char* argv[])
{
	if (argc != 2)
	{
		 printf("Usage: %s -[a,b,c,d]\n", argv[0]);//下标为0的位置,始终会有元素(./程序名)
		 return 1;
	}
	if(strcmp(argv[1], "-a") == 0)
	{
		 printf("this is function1\n");
	}
	else if(strcmp(argv[1], "-b") == 0)
	{
		 printf("this is function2\n");
	}
	else if(strcmp(argv[1], "-c") == 0)
	{
		 printf("this is function3\n");
	}
	else if(strcmp(argv[1], "-d") == 0)
	{
		 printf("this is function4\n");
	}
	else
	{
		 printf("no this function!!\n");
	 }

	for(int i = 0; i < argc; i++)
    {
        printf("argv[%d]->%s\n", i, argv[i]);
    }
}

为什么要有命令行参数:

本质:命令行参数本质是交给我们程序不同的选型,用来定制不同的程序功能。命令行中会携带很多的选项。就像 switch 和 case一样。

命令行解释器(bash)在启动时,会为我们维护一张指针数组表,bash将 ./myprocess -a -b -c -d这条命令,遇到这条命令的空格就分成了 n 个子字符串,将子字符串转换成指针数组表里的元素。

我们再来看接下来的代码:

vim myprocess.c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
int g_val = 100000;
int main()
{
    printf("I am father process, pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val);
    sleep(5);

    pid_t id = fork();
    if(id == 0)
    {
        //child
        while(1)
        {
            printf("I am child process, pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val);
            sleep(1);
        }
    }
    else 
    {
        // father
        while(1)
        {
            printf("I am father process, pid: %d, ppid: %d, g_val: %d\n", getpid(), getppid(), g_val);
            sleep(1);
        }
    }
}

父进程的数据,默认能被子进程看到并访问。

命令行中启动的程序,都会变成进程,其实都是bash的子进程。

三、环境变量

3.1、基本概念

  • 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数,如:我们在编写C/C++代码的时候,在链接的时候,从来不知道我们的所链接的动态静态库在哪里,但是照样可以链接成功,生成可执行程序,原因就是有相关环境变量帮助编译器进行查找。
  • 环境变量通常具有某些特殊用途,还有在系统当中通常具有全局特性。

3.2、常见环境变量

  • PATH : 指定命令的搜索路径
  • HOME : 指定用户的主工作目录(即用户登陆到Linux系统中时,默认的目录)
  • SHELL : 当前Shell,它的值通常是/bin/bash
  • HISTSIZE:默认记录用户输入的最新的1000条的历史命令

3.3、查看环境变量方法

echo $PATH
//显示 PATH 环境变量的内容

3.4、有什么方法可以不用带路径,直接就可以运行呢?

我们自己生成的可执行程序,必须加程序的路径(./)才可以执行;但是Linux中的ls、pwd等这些可执行程序不需要加程序的路径,都可以执行,为什么呢?

Linux中,存在一些全局的设置,表明,告诉命令行解释器,应该去那些路径下,去寻找可执行程序。ls命令的路径是在PATH环境变量当中的,所以执行ls命令,就不用带./

echo $PATH

我们一般执行那个命令的时候,我们的命令行解释器(bash)会先去 PATH 这个环境变量下的所有路径里去找有没有我们对应的可执行程序,如果有,就不用加程序的路径(./)了;如果没有,就得加程序的路径(./)。

强硬的方法:

sudo cp myprocess usr/bin/

我们把我们写的myprocess可执行程序拷贝(安装)到Linux系统里指定的PATH环境变量下的 usr/bin 路径下。

温柔的方法:

把我们写的可执行程序myprocess的路径添加到PATH环境变量里呢?

PATH=/home/song/111/code/lesson

因为PATH是变量,我们可以直接让路径赋值给环境变量,但是我们会把PATH环境变量下的所有路径都给覆盖了,不能这么干。

但是不用担心,因为目前PATH环境变量是我们登录Linux系统的时候,就已经被加载到bash进程当中(内存),现在的环境变量是内存级的(默认我们查到的环境变量是内存级的);实际上环境变量的设置,不仅仅是在内存里,在系统的配置文件里也是有的,我们再重新登录一下Linux系统就可以了。

但是我们依然想要将可执行程序myprocess的路径添加到PATH环境变量里?

PATH=$PATH:/home/song/111/code/lesson

保留原来PATH里的路径,再添加一个路径。

但是这个只是在内存级里设置的,Linux系统重新登录一下,我们添加的路径又会消失。

我们想要我们添加的路径,永久的保存在PATH环境变量里,怎么做呢?

最开始的环境变量不是在内存中,而是默认在系统对应的配置文件中。在登录Linux系统的时候,会创建一个bash进程,系统里的配置文件会被bash进程拷贝一份,所以,我们每次重新登录的时候,PATH下的路径都会回复原样。

系统的配置文件在哪里?

这些配置文件都在属于自己的家目录下。

PATH=$PATH:/home/song/111/code/lesson

我们可以把我们添加的路径,可以通过 PATH=$PATH:/home/song/111/code/lesson它,添加到系统的配置文件中,这样我们每次重新打开Linux系统,我们都可以不带路径(./)来执行可执行程序(myprocess)。

3.5、和环境变量相关的命令

  • echo + $xxx: 显示某个环境变量值
  • export + name=val: 导入一个新的环境变量name
  • env: 显示所有环境变量
  • unset + name: 清除环境变量
  • set: 显示本地定义的shell变量和环境变量

我们导入一个变量 hello=123456 ,但是我们没有写export,我们在所有的环境变量中搜索,并没有找到,但是我们却能够单独把这个变量的内容打印到屏幕上。虽然 hello 变量在环境变量中,但是叫本地变量(身在曹营,心在汉)。

3.6、环境变量的组织方式

每个程序都会收到一张环境变量表,环境变量表是一个字符指针数组,每个指针指向一个以’\0’结尾的环境字符串。

3.7、通过代码如何获取环境变量

通过第三方变量environ获取

#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char* argv[])
{
	// 获取一下环境变量
	extern char** environ;//声明一下 environ
	for(int i = 0; environ[i]; i++)
	{
	    printf("env[%d]->%s\n", i, environ[i]);
	}
}

//字符串可以理解为数组,数组名就是数组首元素的地址
//environ[i]:是指针数组里面的元素,元素是环境变量(字符串)的地址,所以元素就是字符串

libc中定义的全局变量environ指向环境变量表,environ没有包含在任何头文件中,所以在使用时 要用extern声明。

命令行第三个参数

#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char *argv[], char *env[])
 {
    int i = 0;
    for(; env[i]; i++){
        printf("%s\n", env[i]);
    }
    return 0;
 }

磁盘中有系统的配置文件,而配置文件里面包含了环境变量;Linux系统登录,会在内存中加载bash进程。bash进程将配置文件(里面包含,环境变量)里的数据拷贝了一份。

环境变量可是很多的,bash内部是如何组织的呢?

bash在启动时,也会为我们维护一张表,这张表是一个指针数组表(char *env[]),这张表指向的内容都是char*的,所以,每当我们有一个环境变量(就是字符串,如:PATH=/usr/bin:/a/b/c/...),环境变量把对应的字符串,从配置文件加载进来,字符串信息就有了,把字符串的地址填到我们的环境变量表里,环境变量表的最后一位以 NULL 结尾。

bash进程启动的时候,默认会给我们子进程形成两张表:argv[]命令行参数表,env[]环境变量表(从OS的配置文件夹来)。bash通过各种方式交给子进程。

3.8、通过系统调用获取或设置环境变量

putenv , 后面讲解

getenv , 根据环境变量名拿到环境变量的内容,本次讲解

#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>

int main(int argc, char* argv[], char* env[])
{
	char* path = getenv("PATH");
	if (path == NULL) 
		return 1;
	printf("path: %s\n", path);
	for (int i = 0; env[i]; i++)
	{
		printf("env[%d]->%s\n", i, env[i]);
	}

	fork(); // 能!子进程能获得命令行参数和全局变量   bash(父进程) ---> main(子进程) ---> fork()(创建子进程的子进程)
}

常用getenv和putenv函数来访问特定的环境变量。

3.9、环境变量通常是具有全局属性的

  • 环境变量通常具有全局属性,可以被子进程继承下去
#include <stdio.h>
#include <stdlib.h>

int main()
 {
    char * env = getenv("MYENV");
    if(env){
        printf("%s\n", env);
    }
    return 0;
 }

直接查看,发现没有结果,说明该环境变量根本不存在

  • 导出环境变量   export MYENV="hello world"
  • 再次运行程序,发现结果有了!说明:环境变量是可以被子进程继承下去的!想想为什么?

3.10、内建命令

export myval=111111 
//将导入myval成环境变量
echo $myval  
//也能将环境变量myval的内容打印出来(111111)

那么export命令被命令行解释器(bash)运行的时候,不会创建子进程吗?
如果创建子进程,那么export导出来的环境变量就不应该被bash看到。
因为父进程的数据,默认能被子进程看到并访问,是因为创建子进程的时候,子进程是通过fork()继承的方式,看到父进程的。如果子进程导入了一些环境变量做修改了,父进程是看不到的。

但是,我们这里的父进程是能够看到导入环境变量的内容的,这是怎么回事?

那是因为 export 、echo是内建命令,由父进程(bash)亲自执行,并不会创建子进程。


总结

好了,本篇博客到这里就结束了,如果有更好的观点,请及时留言,我会认真观看并学习。
不积硅步,无以至千里;不积小流,无以成江海。

相关推荐

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-03-23 12:20:03       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-03-23 12:20:03       100 阅读
  3. 在Django里面运行非项目文件

    2024-03-23 12:20:03       82 阅读
  4. Python语言-面向对象

    2024-03-23 12:20:03       91 阅读

热门阅读

  1. 【数据库】MySQL索引事务

    2024-03-23 12:20:03       35 阅读
  2. 【复杂网络建模】——通过python的XGI库构建超图

    2024-03-23 12:20:03       33 阅读
  3. Day 29 回溯05

    2024-03-23 12:20:03       41 阅读
  4. 探索MySQL中的SQL_MODE数据模式

    2024-03-23 12:20:03       39 阅读
  5. vue中如何用一个数组减去另一个数组

    2024-03-23 12:20:03       38 阅读
  6. node和npm yarn包管理工具

    2024-03-23 12:20:03       34 阅读
  7. npm 常用命令详解

    2024-03-23 12:20:03       43 阅读
  8. SAP-FI配置与业务解析之代发(客户)销售作业

    2024-03-23 12:20:03       40 阅读
  9. 将uint8_t数组转成uint32_t

    2024-03-23 12:20:03       46 阅读
  10. C++继承

    2024-03-23 12:20:03       40 阅读