0

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

    2023.04.28 | admin | 231次围观

    @TOC

    1. 孤儿进程

    如果父进程一直存在,子进程先退出了,父进程对子进程退出不管不顾,会出现什么样问题么?

    创建makefile并输入以下内容

       mytest:test.c
      2   gcc -o $@ $^ 
      3 .PHONY:clean
      4 clean:
      5   rm -f mytest 
    复制代码

    mytest 属于 目标文件test.c 属于 依赖文件列表@代表目标文件@代表目标文件 @代表目标文件^ 代表依赖文件列表

    创建test.c并输入以下内容

     #include
      2 #include
      3 int main()
      4 {
      5   pid_t id=fork();
      6   if(id==0)
      7   {
      8     //子进程
      9     while(1)
     10     {
     11     printf("我是子进程,我的pid是:%d,我的ppid是%d",getpid(),getppid());
     12     sleep(1);                                                                             
     13     }                                                                                                                                                                
     14     
     15   }
     16   else if(id>0)
     17   {
     18    //父进程
     19    int count=0;//父进程只运行10次
     20     while(1)                        
     21     {                               
     22     printf("我是父进程,我的pid是:%d,我的ppid是%d",getpid(),getppid());
     23     sleep(1);                       
     24     if(count--<=0)                  
     25     {                               
     26       break;                        
     27     }                                                                                                                                      
     28     }                                                                                                                                      
     29   }                                                                                                                                        
     30 }                                         
    复制代码

    复制SSH渠道,创建终端2,在保证终端1mytest运行的情况下,在终端2中输入指令while :; do ps axj | head -1 && ps axj | grep mytest | grep -v grep ; sleep 1; echo "---------"; done

    创建终端方法点击查看

    ---------
     PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
    17835 27831 27831 17835 pts/0    27831 S+    1002   0:00 ./mytest
    27831 27832 27831 17835 pts/0    27831 S+    1002   0:00 ./mytest
    复制代码

    当父子进程刚开始共存时,两者状态都是S+

    PPID   PID  PGID   SID TTY      TPGID STAT   UID   TIME COMMAND
        1 27832 27831 17835 pts/0    17835 S     1002   0:00 ./mytest
    复制代码

    当父进程运行结束后,子进程状态为S

    正常来说,若父子进程中子进程结束,父进程要接收子进程的退出码结果,所以子进程处于僵尸状态但是 父子进程中父进程结束,为什么父进程没有进入僵尸状态呢?

    2. 环境变量

    在操作系统当中由系统在开机之后帮我们维护的一些系统运行时的动态参数

    我们自己写的代码,编译之后,运行的时候,为什么要带 ./ ?

    那为什么运行系统的指令不需要 ./ ?

    1. PATH环境变量

    echo 作为打印字符串的一条命令

    [yzq@VM-8-8-centos ~]$ echo abcd   
    abcd
    复制代码

    echo $PATH 查看环境变量PATH

    [yzq@VM-8-8-centos ~]$ echo $PATH
    /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/mydir/.local/bin:/home/mydir/bin
    复制代码

    /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/mydir/.local/bin:/home/mydir/bin是以冒号作为分隔符,可以分割出来若干子路径

    证明ls是系统指令

    使用which 指令,搜索特定指令所对应的路径

    [yzq@VM-8-8-centos my]$ which ls
    alias ls='ls --color=auto'
        /usr/bin/ls
    复制代码

    ls的路径为 /usr/bin/ls环境变量是从左到右,一条一条去查找,只要找到就停下来ls指令在环境变量的usr/bin 路径下,说明 ls 指令不用带路径

    修改自己写的可执行程序对应路径

    修改自己写的可执行程序的路径,让其不用添加路径即可运行

    创建test.c文件

    #include
      2 int main()
      3 {
      4   printf("hello");                                                                                                                                                   
      5 }                                                                                                                         
           
    复制代码

    输入 gcc -o testc test.c ,生成testc可执行程序输入 which testc ,查询testc的路径

    [yzq@VM-8-8-centos my]$ which testc
    /usr/bin/which: no testc in (/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/mydir/.local/bin:/home/mydir/bin)
    复制代码

    说明 testc路径不在环境变量中

    使用pwd ,查询当前testc的路径,输入 export PATH=$PATH: 当前路径 ,将testc的路径新增到到环境变量中

    [yzq@VM-8-8-centos my]$ pwd
    /home/mydir/my
    [yzq@VM-8-8-centos my]$ export PATH=$PATH:/home/mydir/my
    复制代码

    [yzq@VM-8-8-centos my]$ testc
    hello
    复制代码

    直接 使用 testc ,就运行可执行程序

    2. env——查看系统环境变量

    使用 env ,会出现如下环境变量

    这些环境变量都是用户登录的时候设置好的,都是kv的

    输入 echo $HOSTNAME 显示当前机器 名字

    [yzq@VM-8-8-centos ~]$ echo $HOSTNAME
    VM-8-8-centos
    复制代码

    输入 echo $SHELL 显示当前所使用的shell

    [yzq@VM-8-8-centos ~]$ echo $SHELL
    /bin/bash
    复制代码

    输入 echo $HOME,当前为普通用户

    [yzq@VM-8-8-centos ~]$ echo $HOME
    /home/mydir
    复制代码

    HOME环境变量表示当前用户所对应的家目录

    切换成root用户后, 此时对应root目录

    [root@VM-8-8-centos mydir]# echo $HOME
    /root
    复制代码

    对于不同登录的人,同一个环境变量里面放的不同的内容出现未结束字符串常量错误,重装浏览器能解决吗,所以环境变量是针对特定的人在特定的场景使用的

    3. 获取环境变量envp

    main函数可以带3个参数分别为 int argc 和 char*argv [ ] 和char * envp[ ] (环境变量表)

    创建test.c文件

    #include
        2 #include
        3 int main(int argc,char*argv[],char*envp[])
        4 {
        5   int i=0;
        6   for(i=0;envp[i];i++)
        7   {
        8     printf("envp[%d]->%s\n",i,envp[i]);
        9   }                                                                                                                                                                
       10 }   
    复制代码

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

    创建makefile

       mytest:test.c
      2   gcc -o mytest test.c
      3 .PHONY:clean
      4 clean:
      5   rm -f mytest  
    复制代码

    输入 make ,使用./mytest 执行可执行程序

    发现envp是一张传递给当前进程的环境变量表char类型指针指向环境变量字符串

    environ

    若main函数不传参数,还想要拿到环境变量,可以使用 environ

    修改test.c文件

     #include
        2 #include
        3 int main()
        4 {
        5   extern char** environ;//声明
        6   int i=0;
        7   for(i=0;environ[i];i++)
        8   {
        9     printf("environ[%d]->%s\n",i,environ[i]);
        10   }                                                                                                                                                                
        11 }                                                                                              
           
    复制代码

    使用make, ./mytest执行可执行程序后

    使用environ 也可以拿到所有环境变量

    getenv 函数获取 (主流)

    char* getenv(const char* name);

    修改test.c文件

      1 #include
        2 #include
        3 #include
        4 int main()
        5 {
        6   char*user=getenv("USER");
        7   if(user==NULL)
        8   {
        9     perror("getenv");
       10   }
       11   else 
       12   {
       13     printf("USER:%s\n",user);
       14   }
       15 }   
    复制代码

    输入 make, ./mytest 执行可执行程序

    [yzq@VM-8-8-centos my]$ ./mytest
    USER:yzq
    复制代码

    获取到user的名称

    4. 总结

    环境变量对应的数据,是从系统的相关配置文件中读取进来的使用 cd ~ ,进入当前目录的主目录中使用 ls -la , 显示隐藏文件

    这是两个shell脚本,内部包含了配置文件

    3 . 命令行参数

    main函数的两个参数,char* argv[] 为指针数组 ,argv为一张表,包含一个个指针,指针指向字符串int argc,argc为数组的元素个数

    修改test.c文件

     #include
        2 #include
        #inlcude
        3 #include
        4 int main (int argc,char*argv[])
        5 {
            int i=0;
        6   for(i=0;i7   {
        8     printf("argv[%d]->%s\n",i,argv[i]);
                                                                                                                                                                                      
       10   }
    复制代码

    使用make , ./mytest 执行可执行程序

    [yzq@VM-8-8-centos my]$ ./mytest
    argv[0]->./mytest
    [yzq@VM-8-8-centos my]$ ./mytest -a
    argv[0]->./mytest
    argv[1]->-a
    [yzq@VM-8-8-centos my]$ ./mytest -a -b
    argv[0]->./mytest
    argv[1]->-a
    argv[2]->-b
    复制代码

    ./mytest -a -b,就是一个字符串以空格作为分隔符,形成一个一个的子串第一个./mytest为可执行程序,剩余的统称为参数选项

    理解命令行参数

    修改test.c文件

          #include
        2 #include
        3 #include
        4 #include
        5 void usage(const char*name)
        6 {
        7   printf("\nusage:%s-[a|b|c]\n\n",name);
        8   exit(0);//终止进程
        9 }                                                                                                                                                                
       10 int main  (int argc,char*argv[])                                                                                                                                 
       11 {                                                                                                                                                                
       12   if(argc!=2)                                                                                                                                                    
       13   {                                                                                                                                                              
       14     usage(argv[0]);//argv[0]代表可执行程序  
            }                                                                                                      }                                                                                                                     
       15     if(strcmp(argv[1],"-a")==0)                                                                                                                                  
       16     {                                                                                                                                                            
       17         printf("打印目录下的文件名\n");                                                                                                                          
       18     }                                                                                                                                                            
       19     else if(strcmp(argv[1],"-b")==0)                                                                                                                          
       20     {                                                                                                                                                            
       21       printf("打印目录下的文件的详细信息\n");                                                                                                                    
       22     }                                                                                                                                                            
       23     else if(strcmp(argv[1],"-c")==0)                                                                                                                             
       24     {                                                                                                                                                            
       25       printf("打印目录下文件的隐藏信息\n");
       26     }
       27     else 
       28     {
       29       printf("待未开发\\n");
       30     }
       31                                                                                                                                                                                 
       32 }                       
    复制代码

    使用 make ,./mytest 执行可执行程序

    [yzq@VM-8-8-centos my]$ ./mytest
    usage:./mytest-[a|b|c]
    [yzq@VM-8-8-centos my]$ ./mytest -a
    打印目录下的文件名
    [yzq@VM-8-8-centos my]$ ./mytest -b
    打印目录下的文件的详细信息
    [yzq@VM-8-8-centos my]$ ./mytest -c
    打印目录下文件的隐藏信息
    [yzq@VM-8-8-centos my]$ ./mytest -d
    待未开发
    复制代码

    相当于使用ls 、ls -l 、ls -la 指令,选项以字符串形式以命令行参数传递给了程序,程序内部对选项做判断,就可使同样的ls ,携带不同的选项,就可表现不同的现象

    4. 进程优先级优先级与权限的区分

    权限代表能不能的问题,优先级代表已经能,谁先谁后的问题比如 权限:若你考完试,你能够自己去老师教室翻阅自己的卷子么,当然不能,没有权限优先级:若你在食堂排队,你可以打饭,但是有先后顺序

    为什么会有优先级?查看系统进程的优先级

    ps -l 查看当前系统的进程优先级

    [yzq@VM-8-8-centos my]$ ps -l
    F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
    0 R  1002  3722 17835  0  80   0 - 38324 -      pts/0    00:00:00 ps
    0 S  1002 17835 17834  0  80   0 - 29280 do_wai pts/0    00:00:00 bash
    复制代码

    PRI代表当前进程的优先级NI代表当前进程优先级的修正数据UID代表当前用户的身份标识

    PRI数字值越小,优先级越高PRI(new)=PRI(old)+NI(nice)一般调整的是nice值,nice值取值范围是[-20-19]调度器的作用是一碗水端平,让每一个进程有享有资源,所以不支持将一个进程的PRI调整过小,从而导致优先级过高

    调整进程优先级

    在test.c中修改为以下内容

    #include
      2 #include
      3 int main()
      4 {
      5   while(1)
      6   {
      7     printf(".");
      8     fflush(stdout);//刷新缓冲区
      9     sleep(1);                                                                  
     10   }                                                            
     11   return 0;                                                    
     12 }                                                              
         
    复制代码

    使用./mytest运行程序,并复制SSH渠道 创建终端2

    在保证终端1mytest运行的情况下,在终端2中使用 ps -la ,找到mytest进程

    [yzq@VM-8-8-centos my]$ ps -la
    F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
    0 S  1002  8561 17835  0  80   0 -  1054 hrtime pts/0    00:00:00 mytest
    0 R  1002  9135 23362  0  80   0 - 38332 -      pts/1    00:00:00 ps
    复制代码

    再次在终端2中使用 top 指令,输入 r(renice),出现如下数据

    PID to renice [default pid = 7429] 
    复制代码

    在上一步输入的 ps -la指令中查询mytest的PID

    使用q退出再次输入 ps -la指令

    [yzq@VM-8-8-centos my]$ ps -la
    F S   UID   PID  PPID  C PRI  NI ADDR SZ WCHAN  TTY          TIME CMD
    0 S  1002  8561 17835  0  90  10 -  1054 hrtime pts/0    00:00:00 mytest
    0 R  1002 12141 23362  0  80   0 - 38332 -      pts/1    00:00:00 ps
    复制代码

    发现刚刚修改nice值为10出现未结束字符串常量错误,重装浏览器能解决吗,PID值变为90

    版权声明

    本文仅代表作者观点。
    本文系作者授权发表,未经许可,不得转载。

    发表评论