【linux】环境变量

僵尸状态和孤儿进程

僵尸状态

当子进程处于僵尸状态时,数据以及代码已经被退出,而保留的是他的pcb,然后要等待父进程来回收,如果父进程未回收,子进程的pcb存在在内存,导致内存泄漏

孤儿进程

父进程先退出,等到子进程退出的时候,没有父进程来回收子进程,这种叫做孤儿进程,而对于孤儿进程会被1号init进程领养

孤儿进程演示

c 复制代码
#include<stdio.h>
#include<unistd.h>
 int main()
   {
    size_t id=fork();
    if(id==0)
    {
    while(1)
     {
 
      printf("hello world pid:%d\n",getpid());
      sleep(1);
   }
    }
    else  
    {
      int cnt=5;
      while(cnt)
     {
      printf("hello world pid:%d\n",getpid());
      cnt--;
      sleep(1); }
   }                                                    
  }

为什么要被领养?

子进程退出,父进程早已经不在,子进程需要被进程回收,所以被领养


进程优先级

1.为什么要有优先级?

是因为cpu的资源是有限的,进程太多,需要通过某种方式竞争资源

2.什么是优先级?

确认谁应该先获得某种资源,谁后获得。

我们可以通过一些数据表明优先级的,而评判优先级是通过调度器

linux下的优先级

ps-la指令可以查看到优先级

优先级=老的优先级+Nice值(修正优先级的值)

调整Nice值

步骤:

1.top

2.r

3.进程号

4.输入你要设置的Nice值(-20至19)操作系统让进程在一定程度下保持均衡

==每次调Nice时,pri都默认为80;优先级的值越小,优先级越高


基本概念

竞争性: 系统进程数目众多,而CPU资源只有少量,甚至1个,所以进程之间是具有竞争属性的。为了高

效完成任务,更合理竞争相关资源,便具有了优先级

独立性: 多进程运行,需要独享各种资源,多进程运行期间互不干扰

并行: 多个进程在多个CPU下分别,同时进行运行,这称之为并行

并发: 多个进程在一个CPU下采用进程切换的方式,在一段时间之内,让多个进程都得以推进,称之为并发

独立性解释:多进程运行,需要独享各种资源,多进程运行期间互不干扰,父进程和子进程互不影响。

时间片:在调度进程时,不是将该进程跑完,而是在cpu上跑几ms,然后cpu再调度别的进程,每个进程的时间片到了,就调度别的进程。

抢占与出让:优先级高的进程会将比他优先级低的正在调度的进程抢占cpu资源,让cpu调度优先级高的进程,尽管优先级低的时间片还没到叫做抢占。

出让:正在调度的进程还没有到时间片,就主动退出,让下一个进程调度,叫做出让。


切换进程

cpu中存在寄存器,当进程A被运行的时候,cpu中的寄存器,保存进程A的临时数据,我们直到当一个函数要返回值的时候,由于该变量是局部变量,出来函数就要被销毁,在销毁前,变量会将他的值保存在寄存器里面,然后返回。寄存器中的临时文件,叫做A的上下文。

上下文可以被丢弃吗??

不可以,当进程A被切换走,会带走他的上下文数据(保存在pcb中),为了下次回来的时候,能恢复上去,从上次执行那里接着执行。

而cpu寄存器只有一份,而上下文有多份,对于不同的进程。

命令行参数

大家在写main函数的时候默认省略了参数

c 复制代码
int main(int  argc , char*argv[])

main函数的参数可带可不带

这些参数的意义到底是啥??

先写一段代码

c 复制代码
 #include<stdio.h> 
 #include<unistd.h>
 int main(int argc, char *argv[])
  {
 for(int i=0;i<argc;i++)
    {
     printf("argv[%d]:%s\n",i,argv[i]);
     
     
   }
                                                                                                                     
   }

char *argv[]是一个指针数组,而argc是指针数组的元素个数,我们通过for循环,打印指针数组里面的内容看看到底是什么

这段代码c99不支持这样写,应该将int i定义在外面。

当我们执行该可执行程序的时候,他会把我们的输入指令转换为字符串,将每段字符串的地址存在数组中
默认在指针数组最后一个是NULL,如何进行验证??

c 复制代码
 #include<stdio.h>
     #include<unistd.h>
   int main(int argc, char *argv[])
     {int i;
     for( i=0;argv[i];i++)                                                                                            
     {
     printf("argv[%d]:%s\n",i,argv[i]);
     
    
    }
    
    }

将黄色的地方换成了argv[i],当执行这个程序时,当到最后一个指针数组元素时,为NULL,for循环终止,程序不会陷入循环。

1.为什么要有命令行参数??

本质:命令行参数本质是交给我们程序的不同选型,用来定制不同的功能。命令中会携带很多选项,下面的代码就可以解释。

c 复制代码
#include<stdio.h>
   #include<unistd.h>
  #include<string.h>
  int main(int argc, char *argv[])
  {
  if(argc!=2)
   {
     printf("usage: %s -[a,b,c,d]\n",argv[0]);
     return 1;
  }
  if(strcmp(argv[1],"-a")==0)
  {
  printf("功能1\n");}
  else if(strcmp(argv[1],"-b")==0)
  {
  printf("功能2\n");
  }
 
 else if(strcmp(argv[1],"-c")==0)
  {
  printf("功能3\n");                                                                                                 
  }
  else if(strcmp(argv[1],"-d")==0)
  {
  printf("功能4\n");
  }
  }

代码解释:第一个if语句是判断如果没有带选项,就模拟别的指令那样,让你加选项,没带选项的话,对应的argc!=2,然后分情况判断输入的选项是啥,执行对应的功能,,这样就模拟输入linux指令+对应选项,就会输出对应选项的功能。

2.是谁这样干的?

解答这个问题之前,我们要验证一个东西,就是父进程的数据,默认能被子进程看到并访问(通过代码验证)

c 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>
 int ret=10000;
 int main()
   {
    printf("i am father pid=%d,ppid=%d\n",getpid(),getppid());                                                        
   sleep(1);
   
   size_t id=fork();
   if(id==0)
   {
    while(1)
    {
    printf("i am child  pid=%d,ppid=%d,ret=%d\n",getpid(),getppid(),ret);
  
  
 
  }
  }}

fork后的子进程可以访问到父进程全局的变量数据,也就是父进程的数据,默认能被子进程看到并访问

默认输入的指令都是给父进程bash的,然后父进程bash会通过输入的指令字符串,给子程序执行相应的功能


环境变量

当我们执行我们的可执行程序时,我们发现我们的可执行程序要带路径,比如说这个程序res.exe, 我们执行它时,必须要加./来运行,像linux里面的指令,它可以直接运行,不用加./这是为什么呢??

是因为,linux里面有些存在全局的设置,告诉命令行解释器,应该去那些路径下去寻找可执行程序

这里不得不讲PATH这个环境变量,他会记录我们linux指令(相当于程序),所在的路径,而执行相关的命令时,他会在这个环境变量里面存的路径里面找对应的指令(相当于程序)

我们可以使用vim来查看路径下的程序

我们找到了一个认识的kill指令


我们可以讲我们可执行程序的路径,拷贝到/usr/bin下面的话,我们就不用在加路径,而是在PATH环境变量中路径里面找可执行程序

我们可以新建一个.c文件,然后将他的路径拷贝到/usr/bin,我们试一试看在执行的时候需不需要带路径




我们将ui.exe拷贝到/usr/bin路径下,我们发现可以不用加./路径就可以运行。

但是我们默认查到的环境变量时内存级的,这种方法会一直保存

将该可执行程序的路径从环境变量中删除,无法在不加路径运行了

以上这种·方式不建议,用起来可以永久使用,但是会污染环境变量


我们还有一种方法将我们的ui.exe的路径放到PATH环境 变量中去

如果我们采用这种方式的话,会将PATH中的原路径进行覆盖式删除,导致我们之前的指令用不了,比如说ls

我们可以通过echo $PATH来看看

那应该如何添加呢??

这样就可以了

但是这种环境变量还是内存级别的。断开在连接的时候,环境变量中就没有你之前添加的路径了(演示如下)


有什么方法可让x-shell断开在连接时,不会修改我们添加进去的路径,我们可以看到

当x-shell打开时,我们的PATH环境变量会直接添加有些程序的路径,本质上这些环境变量存在于配置文件中,而配置文件在家目录的隐藏目录下

我们可以通过ls-la查看到

我们通过vim打开这两个文件

我们通过vim打开

然后断开连接,然后再次连接就可以了

bash在执行命令的时候,需要先找到命令,因为未来要加载。
再次强调:最开始的环境变量不是在内存中的,而是在系统的配置文件中,而环境变量是在配置文件中


其他的环境变量

1.HOME

该环境变量中保存是对应用户的家目录路径,用户登陆默认在家目录,是因为该环境变量中保存着

2.SHELL

用户使用的shell解释器名称

3.HISTSIZE

保存最近使用指令的个数

我们可以通过history指令查看到最近的1000个指令

4.PWD

该环境变量保存着当前路径,会随着路径切换,不断的变化


关于环境变量相关的指令

env 可以查看所有的环境变量
echo $环境变量名 查看对应的环境变量
export 环境变量名 添加环境变量
-- --
unset 环境变量名 取消环境变量





我们再次env发现找不到了


代码方式获取环境变量

在头文件unistd.h中存在一个变量 char** environ

bash内部这样组织我们的环境变量

我们通过程序将环境变量打印出来

c 复制代码
  #include<stdio.h>
   #include<unistd.h>
  #include<string.h>                                                                                                 
   int main()                           
   {                                    
   extern char** environ;               
   int i;                               
   for(i=0;environ[i];i++)              
   {                                                                        
  printf("env[%d]->%s\n",i,environ[i]);                                       
                                                                           
  }                                                                        
                                                                           
                                       
                                       
                                      
                                      
                                       
                                       
  } 


环境变量具有系统的全局属性,因为环境变量本身会被子进程继承下去


另一种方式

main函数可以通过传参的方式将环境变量表给子进程

代码如下:

c 复制代码
#include<stdio.h>
#include<unistd.h>
#include<string.h>                                                                                                      int main (int argc,char *argv[],char *env[])                                                                  
  {  int i;
        for(i=0;env[i];i++)
        {
        printf("env[%d]->%s\n",i,env[i]);
   
        }
   
      }

当bash进程启动时,默认给两张表,一个命令行参数表,一个环境变量表

命令行参数表来源于用户的命令行,而环境变量表来源于配置文件


第三种方法

:通过getenv

头文件:stdlib.h


内建命令

80%的命令是bash创建子进程执行的,而有一部分指令是bash亲自完成的,叫做内建指令,在之前我们通过将PATH环境变量中的路径覆盖后,有些指令就用不了了,有一些可以用,比如说echo ,export(属于内建命令),可能bash通过创建函数的方式实现内建命令。

相关推荐
热爱嵌入式的小许12 分钟前
Linux基础项目开发1:量产工具——显示系统
linux·运维·服务器·韦东山量产工具
韩楚风4 小时前
【linux 多进程并发】linux进程状态与生命周期各阶段转换,进程状态查看分析,助力高性能优化
linux·服务器·性能优化·架构·gnu
陈苏同学4 小时前
4. 将pycharm本地项目同步到(Linux)服务器上——深度学习·科研实践·从0到1
linux·服务器·ide·人工智能·python·深度学习·pycharm
Ambition_LAO4 小时前
解决:进入 WSL(Windows Subsystem for Linux)以及将 PyCharm 2024 连接到 WSL
linux·pycharm
Pythonliu74 小时前
茴香豆 + Qwen-7B-Chat-Int8
linux·运维·服务器
你疯了抱抱我4 小时前
【RockyLinux 9.4】安装 NVIDIA 驱动,改变分辨率,避坑版本。(CentOS 系列也能用)
linux·运维·centos
追风赶月、4 小时前
【Linux】进程地址空间(初步了解)
linux
栎栎学编程4 小时前
Linux中环境变量
linux
我是哈哈hh5 小时前
专题十_穷举vs暴搜vs深搜vs回溯vs剪枝_二叉树的深度优先搜索_算法专题详细总结
服务器·数据结构·c++·算法·机器学习·深度优先·剪枝
郭二哈5 小时前
C++——模板进阶、继承
java·服务器·c++