【linux】环境变量

僵尸状态和孤儿进程

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

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

孤儿进程演示

#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函数的时候默认省略了参数

int main(int  argc , char*argv[])

main函数的参数可带可不带
这些参数的意义到底是啥??
先写一段代码

 #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,如何进行验证??

 #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.为什么要有命令行参数??
本质:命令行参数本质是交给我们程序的不同选型,用来定制不同的功能。命令中会携带很多选项,下面的代码就可以解释。

#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.是谁这样干的?
解答这个问题之前,我们要验证一个东西,就是父进程的数据,默认能被子进程看到并访问(通过代码验证)

#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内部这样组织我们的环境变量
我们通过程序将环境变量打印出来

  #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函数可以通过传参的方式将环境变量表给子进程
代码如下:

#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通过创建函数的方式实现内建命令。

相关推荐

  1. linux设置环境变量

    2024-03-22 06:38:01       41 阅读
  2. Linux环境变量

    2024-03-22 06:38:01       35 阅读
  3. Linux 环境变量

    2024-03-22 06:38:01       24 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-22 06:38:01       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-22 06:38:01       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-22 06:38:01       19 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-22 06:38:01       20 阅读

热门阅读

  1. 【Docker】常用命令 docker network ls

    2024-03-22 06:38:01       19 阅读
  2. 我的创作纪念日

    2024-03-22 06:38:01       21 阅读
  3. hive的小文件如何处理

    2024-03-22 06:38:01       20 阅读
  4. ArcGis 地图文档

    2024-03-22 06:38:01       18 阅读
  5. 如何判断对象可以被回收

    2024-03-22 06:38:01       21 阅读
  6. 替换老版本包和模块-版本回滚-依赖冲突

    2024-03-22 06:38:01       22 阅读
  7. spring boot 解决前端处理Long溢出问题(转字符串)

    2024-03-22 06:38:01       19 阅读
  8. CHAT~

    2024-03-22 06:38:01       18 阅读
  9. 前后端分离开发

    2024-03-22 06:38:01       19 阅读