【linux】进程等待,进程替换


前面内容是关于进程创建和终止的内容,这里主要是进程等待和替换。

1.进程等待

1.1进程等待必要性

前面进程状态说过僵尸进程。

1.子进程退出,如果父进程对其不管不顾,就有可能造成僵尸进程,进而造成内存泄漏。
2.此外,处于僵尸的进程,已经处于退出状态了,就算使用kill -9也没有办法杀掉一个已经死掉的进程。
3.最后,父进程派给子进程的任务完成得如何,我们需要知道,如,子进程运行完成,结果是对还是不对,或者是否正常退出。

对于上述问题我们该如何解决呢?

就是通过今天讲的进程等待得方法来解释上述问题。

父进程通过进程等待的方式:回收子进程资源,获取子进程退出信息。

1.2进程等待的方法

1.2.1wait方法

在这里插入图片描述
status这个参数下面讲。
在这里插入图片描述
成功时,返回要等待进程的id。失败,返回-1;

下面这段代码,演示进程等待。

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/wait.h>
  6     
  7 int main()                             
  8 {
    
                                          
  9 
 10     pid_t id=fork();                   
 11     if(id == 0)                        
 12     {
    
                                                                                                                                                                
 13         //子进程                       
 14         int cnt=10;                    
 15         while(cnt)                                                                       
 16         {
    
                                                                                    
 17             printf("我是子进程, pid:%d, ppid:%d, cnt = %d\n",getpid(),getppid(),cnt--);  
 18             sleep(1);                  
 19         }                              
 20         exit(1);                       
 21     }                                  
 22     //父进程                           
 23     sleep(15);                         
 24     pid_t ret=wait(NULL);              
 25     printf("wait success:%d",ret);     
 26     sleep(2);                          
 27     return 0;                          
 28 }  

当子进程退出时,处于僵尸状态(Z+),然后等到父进程对其回收子进程资源。这里wait参数设为NULL;主要是为了演示这一过程。下面就详细说这个参数。

 while :;do ps ajx | head -1 && ps ajx | grep 'mytest' | grep -v grep; sleep 1; done   //循环执行这条指令

在这里插入图片描述

1.2.2waitpid方法

在这里插入图片描述
第一个参数是要等待的进程id,第二个参数获得子进程退出码,第三个参数是等待方式暂时默认为0(阻塞等待)。

  1 #include<stdio.h>  
  2 #include<unistd.h>  
  3 #include<stdlib.h>  
  4 #include<sys/types.h>                      
  5 #include<sys/wait.h>                      
  6                                            
  7 int main()                                 
  8 {
    
                                              
  9                                            
 10     pid_t id=fork();                       
 11     if(id == 0)                            
 12     {
    
                                          
 13         //子进程                           
 14         int cnt=5;                         
 15         while(cnt)                         
 16         {
    
                                                                                            
 17             printf("我是子进程, pid:%d, ppid:%d, cnt = %d\n",getpid(),getppid(),cnt--);          
 18             sleep(1);                                                                            
 19         }                                                                                        
 20         exit(1);                                                                                 
 21     }                                                                                            
 22     //父进程                                                                                     
 23     sleep(10);  
 24     int status=0;  
 25    // pid_t ret=wait(NULL);  
 26     pid_t ret=waitpid(id,&status,0);
 27    // printf("wait success:%d",ret);
 28		if(ret>0)
 29	    {
    
    
 30    		printf("wait success:%d,ret:%d\n",ret,status);
 31		}
 32     sleep(2);
 33     return 0;                                                                                                                                                    
 34 }    

在这里插入图片描述
退出码256,我们的退出码135个,这里是肯定不对的。

获取子进程status

1.wait和waitpid,都有一个status参数,该参数是一个输出型参数,由操作系统填充。
2.如果传递NULL,表示不关心子进程的退出状态信息。
3.否则,操作系统会根据该参数,将子进程的退出信息反馈给父进程。
4.status不能简单的当作整形来看待,可以当作位图来看待,具体细节如下图(只研究status低16比特位):

在这里插入图片描述
次低8位是退出码,看运行完,结果是否正确。
低7位标表示进程是否正常结束。如果是0表示正常结束,这个时候退出码才有意义。如果是!0退出码不管什么都没有意义。

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/wait.h>                                                                                                                                             
  6 
  7 int main()
  8 {
    
    
  9 
 10     pid_t id=fork();
 11     if(id == 0)
 12     {
    
    
 13         //子进程
 14         int cnt=5;
 15         while(cnt)
 16         {
    
    
 17             printf("我是子进程, pid:%d, ppid:%d, cnt = %d\n",getpid(),getppid(),cnt--);
 18             sleep(1);
 19         }
 20         exit(1);
 21     }
 22     //父进程
 23     sleep(10);
 24     int status=0;
 25    // pid_t ret=wait(NULL);
 26     pid_t ret=waitpid(id,&status,0);
 27    // printf("wait success:%d",ret);
 28    // printf("wait success:%d,ret:%d\n",ret,status);
 29		if(ret>0)
 30		{
    
    
 31	      printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);
 32		}
 33
 34     sleep(2);
 35     return 0;
 36 }

在这里插入图片描述
再看一段退出信号不是0的代码

  1 #include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/wait.h>
  6     
  7 int main()
  8 {
    
    
  9 
 10     pid_t id=fork();
 11     if(id == 0)
 12     {
    
    
 13         int *p=NULL;
 14         //子进程
 15         int cnt=5;
 16         while(cnt)
 17         {
    
    
 18             printf("我是子进程, pid:%d, ppid:%d, cnt = %d\n",getpid(),getppid(),cnt--);
 19             sleep(1);
 20             //让子进程立刻退出
 21             *p=10;
 22         }
 23         exit(1);
 24     }
 25     //父进程
 26    // sleep(10);
 27     sleep(2);                                                                                                                                                    
 28     int status=0;                                              
 29    // pid_t ret=wait(NULL);                                    
 30     pid_t ret=waitpid(id,&status,0);                           
 31    // printf("wait success:%d",ret);                           
 32    // printf("wait success:%d,ret:%d\n",ret,status);           
 33		if(ret>0)
 34		{
    
    
 35	      printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);
 36		}
 37     sleep(2);                                                  
 38     return 0;                                                  
 39 }   

在这里插入图片描述

退出信号不为0,退出码是谁都没有意义。这里显示0是因为我们status传递的是0。

kill -l //查看退出信号是什么

在这里插入图片描述

那么子进程退出码父进程是如何拿到的呢?

在这里插入图 片描述

1.2.3通过宏得到退出码

每次得到退出码,退出信号。输出的时候都需要自己去手动写,系统给我们提供一个宏替换,方便使用。

#include<stdio.h>
  2 #include<unistd.h>
  3 #include<stdlib.h>
  4 #include<sys/types.h>
  5 #include<sys/wait.h>
  6     
  7 int main()
  8 {
    
    
  9 
 10     pid_t id=fork();
 11     if(id == 0)
 12     {
    
    
 13         //int *p=NULL;
 14         //子进程
 15         int cnt=5;
 16         while(cnt)
 17         {
    
    
 18             printf("我是子进程, pid:%d, ppid:%d, cnt = %d\n",getpid(),getppid(),cnt--);
 19             sleep(1);
 20             //让子进程立刻退出
 21            // *p=10;
 22         }
 23         exit(1);
 24     }
 25     //父进程
 26    // sleep(10);       
 27     sleep(2);                   
 28     int status=0;   
 29    // pid_t ret=wait(NULL);  
 30     pid_t ret=waitpid(id,&status,0);  
 31     if(ret>0)  
 32     {
    
             
 33         //判断是否正常退出                                                                                                                                       
 34         if(WIFEXITED(status))
 35         {
    
              
 36             //判断子进程运行结果是否正确  
 37             printf("exit code:%d\n",WEXITSTATUS(status));
 38         }
 39         else
 40         {
    
    
 41             printf("child exit not normal!\n");
 42         }
 43     }
 44     return 0;

在这里插入图片描述

1.2.4 阻塞vs非阻塞

前面我们说了waitpid第三个参数,默认为0,为阻塞状态。
下面讲过小故事帮助理解阻塞,非阻塞。

马上就是期末考试了,张三想找李四恶补一下知识点。于是就约在李四宿舍楼下等他,张三到了之后给李四打电话,李四说他现在在忙其他事情需要一些事情,张三说没事,也没挂电话,就一直等着李四问他好了没。一直等到李四忙好才一起去补习知识点。

又一次快到期中考试了,张三又想找李四帮忙恶补一下知识点。还是老地方等着李四。张三这次还是到了之后给李四打电话,李四还是有事情要忙要等一会,但是这次张三挂了电话,然后一会给王五打电话,一会给其他人打招呼。然后才再给李四打电话。李四没好,张三又挂了电话,去忙其他事情,多次问了李四之后,李四才忙好,去给张三补习。

1.第一种张三不挂电话,检测李四状态--------阻塞
2.第二种张三给李四打电话,如果没有就绪,直接返回------这里每一次都是非阻塞等待,多次非阻塞等待------->轮询。

打电话—>系统调用wait/waitpid
张三—>父进程
李四—>子进程

见识见识非阻塞

    1 #include<stdio.h>
    2 #include<unistd.h>
    3 #include<stdlib.h>
    4 #include<sys/types.h>
    5 #include<sys/wait.h>
    6     
    7 int main()
    8 {
    
    
    9 
   10     pid_t id=fork();
   11     if(id == 0)
   12     {
    
    
   13        // int *p=NULL;
   14         //子进程
   15         int cnt=5;
   16         while(cnt)
   17         {
    
    
   18             printf("我是子进程, pid:%d, ppid:%d, cnt = %d\n",getpid(),getppid(),cnt--);
   19             sleep(1);
   20             //让子进程立刻退出
   21            // *p=10;
   22         }
   23         exit(1);
   24     }

  25     //父进程
 26    // sleep(10);
 27     int status=0;
 28     while(1)//轮询
 29     {
    
    
 30         pid_t ret=waitpid(id,&status,WNOHANG);//非阻塞。子进程没有退出,父进程检测的时候,立即返回
 31         if(ret == 0)
 32         {
    
       //waitpid 调用成功 && 子进程没退出
 33              printf("wait done,but child is runing.....\n");
 34         }
 35         else if(ret > 0)
 36         {
    
    
 37             //waitpid 调用成功 && 子进程退出了
 38             printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);
 39             break;
 40         }
 41         else
 42         {
    
    
 43             //调用失败
 44             printf("waitpid call failed\n");
 45             break;
 46         }
 47			sleep(1);  
 48     }                         
 49     return 0;

在这里插入图片描述

非阻塞的好处:不会占用父进程的所有精力,可以在轮询期间干干别的。

2.进程替换

前面使用fork创建子进程,创建子进程的目的是什么呢?

2.1进程替换的目的

a.想让子进程执行父进程代码的一部分
执行父进程对应的磁盘代码的一部分

b.想让子进程执行一个全新程序
让子进程想办法,加载到磁盘上指定的程序。执行新程序的代码和数据 。

见识一下如何进行进程替换的。

2.2execl替换函数

在这里插入图片描述

在这里插入图片描述

  1 #include<stdio.h>
  2 #include<assert.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/wait.h>
  7 
  8 
  9 int main()
 10 {
    
    
 11     printf("process is runing\n");
 12     //所有exec系列接口,都必须在传参结束的时候,以NULL结尾                                                                                                       
 13     execl("/usr/bin/ls","ls","-l",NULL);
 14     printf("hello\n"); 
 15                        
 16     return 0;          
 17 }    

在这里插入图片描述

  1 #include<stdio.h>
  2 #include<assert.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/wait.h>
  7 
  8 
  9 int main()
 10 {
    
    
 11     printf("process is runing\n");
 12     //所有exec系列接口,都必须在传参结束的时候,以NULL结尾
 13     //给可执行程序增加颜色
 14     execl("/usr/bin/ls","ls","-l","--color=auto",NULL);                                                                                                          
 15     printf("process running done...\n");
 16 
 17     return 0;
 18 }

在这里插入图片描述

见识见识猪跑后。理解理解原理。

2.3理解原理

在这里插入图片描述

程序替换的本质:就是将指定程序的代码和数据加载到指定的位置!覆盖自己的代码和数据。

所以进程替换的是没有创建新的进程。

exexl后面的printf没有执行了,是因为printf也是代码,是在execl之后的,execl执行完毕的时候,代码已经被全部覆盖了,开始执行新的程序的代码了,所以printf就无法执行。

execl调用失败,就是没有替换成功。
在这里插入图片描述
并且exec系列还没有返回值,因为成功了,就和接下来的代码无关了,判断毫无意义,excel只要返回了,一定是错误了。

那么子进程替换会影响父进程码?

  1 #include<stdio.h>
  2 #include<assert.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/wait.h>
  7 
  8 
  9 int main()
 10 {
    
    
 11     pid_t id=fork();
 12     assert(id != -1);
 13     if(id == 0)
 14     {
    
    
 15         //子进程
 16         execl("/usr/bin/ls","ls","-l","--color=auto",NULL);
 17         exit(1);
 18     }
 19     //父进程
 20     int status=0;
 21     pid_t ret=waitpid(id,&status,0);
 22     if(ret > 0)
 23     {
    
    
 24         printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);
 25     }
 26		return 0;

在这里插入图片描述
由上面结果得知:子进程替换,并不是影响父进程,是因为虚拟地址空间+页表保证进程独立性,一旦有执行流想要替换代码或者数据,发生写时拷贝。

2.4其他替换接口

2.4.1execl

1int execl(const char *path, const char *arg, …)

l---->list:将参数一个一个传入execl

2.4.2execlp

int execlp(const char *file, const char *arg, …)

p---->path:解决如何找到程序的功能,带p字符的函数,不用告诉我程序的路径,你只要告诉我是谁,我会自动在环境变量PATH,进行可执行程序的查找。

  1 #include<stdio.h>
  2 #include<assert.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/wait.h>
  7 
  8 
  9 int main()
 10 {
    
    
 11     pid_t id=fork();
 12     assert(id != -1);
 13     if(id == 0)
 14     {
    
    
 15         //子进程
 16        // execl("/usr/bin/ls","ls","-l","--color=auto",NULL);
 17        // 这里有两个ls,其实并不重复,一个是告诉系统我要执行谁,一个是告诉系统,我想怎么执行                                                                     
 18         execlp("ls","ls","-l","--color=auto",NULL);                                                  
 19         exit(1);                                                                                     
 20     }                                                                                                
 21     //父进程                                                                                         
 22     int status=0;                                                                                    
 23     pid_t ret=waitpid(id,&status,0);                                                                 
 24     if(ret > 0)                                                                                       
 25     {
    
                                                                                                     
 26         printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);
 27     }
 28		return 0;   

在这里插入图片描述

2.4.3execv

int execv(const char *path, char *const argv[]);

v----->vector:可以将所有的执行参数,放入数组中,统一传递,而不用使用可变参数方案

    1 #include<stdio.h>
    2 #include<assert.h>
    3 #include<stdlib.h>
    4 #include<unistd.h>
    5 #include<sys/types.h>
    6 #include<sys/wait.h>
    7 
    8 
    9 int main()
   10 {
    
    
   11     pid_t id=fork();
   12     assert(id != -1);
   13     if(id == 0)
   14     {
    
    
   15         //子进程
   16        // execl("/usr/bin/ls","ls","-l","--color=auto",NULL);
   17        // 这里有两个ls,其实并不重复,一个是告诉系统我要执行谁,一个是告诉系统,我想怎么执行
   18        // execlp("ls","ls","-l","--color=auto",NULL);
   19         char* const argv[]={
    
    "ls","-l","--color=auto",NULL};
   20         execv("/usr/bin/ls",argv);                                                                                                                             
   21         exit(1);
   22     }
   23     //父进程
   24     int status=0;
   25     pid_t ret=waitpid(id,&status,0);
   26     if(ret > 0)
   27     {
    
    
   28         printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);
   29     }
   30	  return 0;

在这里插入图片描述

2.4.4execvp

int execvp(const char *file, char *const argv[]);

   13     if(id == 0)
   14     {
    
    
   15         //子进程
   16        // execl("/usr/bin/ls","ls","-l","--color=auto",NULL);
   17        // 这里有两个ls,其实并不重复,一个是告诉系统我要执行谁,一个是告诉系统,我想怎么执行
   18        // execlp("ls","ls","-l","--color=auto",NULL);
 19         char* const argv[]={
    
    "ls","-l","--color=auto",NULL};
   20        // execv("/usr/bin/ls",argv);
   21         execvp("ls",argv);                                                                                                                                   
   22         exit(1);                                                                 
   23     }                                                                            
   24     //父进程                                                                     
   25     int status=0;                                                                
   26     pid_t ret=waitpid(id,&status,0);                                             
   27     if(ret > 0)                                                                  
   28     {
    
                                                                                
   29         printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);
   30     }     

在这里插入图片描述
以上都是执行系统命令,那如果想执行我们自己写的程序呢?

  1 #include<stdio.h>
  2                                                                                                                                                                  
  3 //myexe
  4 int main()
  5 {
    
    
  6     printf("我是一个C程序\n");
  7     printf("我是一个C程序\n");
  8     printf("我是一个C程序\n");
  9     printf("我是一个C程序\n");
 10     printf("我是一个C程序\n");
 11     printf("我是一个C程序\n");
 12     printf("我是一个C程序\n");
 13     printf("我是一个C程序\n");
 14                               
 15     return 0;
 16 } 

我们知道make默认从上到下扫描文件,形成一个可执行目标文件。默认扫描第一个。如果想一次执行多个命令,怎么做?

 .PHONY:all
 all: mytest myexe
 
 mytest:test.c
     gcc -o $@ $^ -std=c11
 
 myexe:myexe.c
     gcc -o $@ $^ -std=c11
     
 .PHONY:clean
 clean:
     rm -f mytest myexe  

被PHONY修饰的是伪对象。这样一次形成两执行。

在这里插入图片描述

    1 #include<stdio.h>
    2 #include<assert.h>
    3 #include<stdlib.h>
    4 #include<unistd.h>
    5 #include<sys/types.h>
    6 #include<sys/wait.h>
    7 
    8 
    9 int main()
   10 {
    
    
   11     pid_t id=fork();
   12     assert(id != -1);
   13     if(id == 0)
   14     {
    
    
   15         //子进程
   16        // execl("/usr/bin/ls","ls","-l","--color=auto",NULL);
   17        // 这里有两个ls,其实并不重复,一个是告诉系统我要执行谁,一个是告诉系统,我想怎么执行
   18        // execlp("ls","ls","-l","--color=auto",NULL);
W> 19         char* const argv[]={
    
    "ls","-l","--color=auto",NULL};
   20        // execv("/usr/bin/ls",argv);
   21         //  execvp("ls",argv);
   22         //执行自己写的程序,这里第二个参数可以不带./
   23         execl("./myexe","myexe",NULL);                                                                                                                         
   24         exit(1);                                                                                    
   25     }                                                                                                                                 
   26     //父进程                                                                                                                          
   27     int status=0;                                                                                                                     
   28     pid_t ret=waitpid(id,&status,0);                                                                                                  
   29     if(ret > 0)                                                                                                                       
   30     {
    
                                                                                                                                     
   31         printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);                                
   32     }   

在这里插入图片描述

注意:可以执行不同语言的可执行程序。

  1 #include<iostream>
  2 using namespace std;
  3 
  4 int main()
  5 {
    
    
  6     cout<<"hello C++"<<endl;                                                                                                                                     
  7     cout<<"hello C++"<<endl;
  8     cout<<"hello C++"<<endl;
  9     cout<<"hello C++"<<endl;
 10     cout<<"hello C++"<<endl;
 11     cout<<"hello C++"<<endl;
 12     return 0;               
 13 }            
~

在这里插入图片描述
还可以使用python,java等等进行替换。

程序替换,可以使用程序替换,调用任何后端语言对应的可执行程序。

2.4.5 execle

int execle(const char *path, const char *arg, …, char * const envp[]);

e:传入自定义环境变量

    1 #include<stdio.h>
    2 #include<assert.h>
    3 #include<stdlib.h>
    4 #include<unistd.h>
    5 #include<sys/types.h>
    6 #include<sys/wait.h>
    7 
    8 
    9 int main()
   10 {
    
    
   11     pid_t id=fork();
   12     assert(id != -1);
   13     if(id == 0)
   14     {
    
    
W> 15         char* const envp[]={
    
    (char*)"MYENV=11223344"};
   16         execle("./myexe","myexe",NULL,envp);                                                                                                                                                                                                                                          
   17         exit(1);                                                                                                                                            
   18     }                                                                                                                                                       
   19     //父进程                                                                                                                                                
   20     int status=0;                                                                                                                                           
   21     pid_t ret=waitpid(id,&status,0);                                                                                                                        
   22     if(ret > 0)                                                                                                                                             
   23     {
    
                                                                                                                                                           
   24         printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);                                                      
   25     } 
   26	  return 0;                                 
  1 #include<stdio.h>
  2 #include<stdlib.h>
  3 
  4 int main()
  5 {
    
    
  6     //系统自带                                                                                                                                                   
  7     printf("PATH:%s\n",getenv("PATH"));
  8     printf("PWD:%s\n",getenv("PWD"));
  9     //自定义环境变量
 10     printf("MYENV:%s\n",getenv("MYENV"));
 11     printf("我是一个C程序\n");
 12     printf("我是一个C程序\n");
 13     printf("我是一个C程序\n");
 14     printf("我是一个C程序\n");
 15     printf("我是一个C程序\n");
 16     printf("我是一个C程序\n");
 17     printf("我是一个C程序\n");
 18     printf("我是一个C程序\n");
 19 
 20     return 0;
 21 }

在这里插入图片描述
注意,传入自定义环境变量,在myexe中,只会显示自定义环境变量的值,系统自带的环境变量不显示。

如果想打印出系统自带的环境变量,需要使用系统提供给我们的environ。

  1 #include<stdio.h>
  2 #include<assert.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/wait.h>
  7   
  8   
  9 int main()  
 10 {
    
      
 11     pid_t id=fork();  
 12     assert(id != -1);  
 13     if(id == 0)  
 14     {
    
      
 15         extern char**environ;
 16			//即使不传,子进程也能获取环境变量                                                                                                 
 17      execle("./myexe","myexe",NULL,environ);
 18			//两种写法都可以
 19         //execle("./myexe","myexe",NULL);                                                                                                                                      
 20         exit(1);                                                                                                         
 21     }                                                                                                                    
 22     //父进程                                                                                                             
 23     int status=0;                                                                                                        
 24     pid_t ret=waitpid(id,&status,0);                                                                                     
 25     if(ret > 0)                                                                                                          
 26     {
    
                                                                                                                        
 27         printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);                   
 28     }  
 29     return 0;

在这里插入图片描述
如果即想要显示自定义环境变量,又想要显示系统默认的环境变量,就将指定环境变量导入到系统中,也就是environ指向的环境变量表

在这里插入图片描述

  1 #include<stdio.h>
  2 #include<assert.h>
  3 #include<stdlib.h>
  4 #include<unistd.h>
  5 #include<sys/types.h>
  6 #include<sys/wait.h>
  7 
  8 
  9 int main()
 10 {
    
    
 11     pid_t id=fork();
 12     assert(id != -1);
 13     if(id == 0)
 14     {
    
    
 15         putenv((char*)"MYENV=11223344");//将指定环境变量导入到系统中 environ指向的环境变量表                                                                                                                         
 16         extern char**environ;                                                                                               
 17         execle("./myexe","myexe",NULL,environ);  
 18			exit(1);                                                                                                         
 19     }                                                                                                                    
 20     //父进程                                                                                                             
 21     int status=0;                                                                                                        
 22     pid_t ret=waitpid(id,&status,0);                                                                                     
 23     if(ret > 0)                                                                                                          
 24     {
    
                                                                                                                        
 25         printf("wait success:%d,sig number:%d,child exit code:%d\n",ret,status&0x7F,(status>>8)&0xFF);                   
 26     }  
 27     return 0;

在这里插入图片描述

我们知道可执行程序是一个文件,放在磁盘里的,要程序要运行的时候,需要加载到内存,为什么要加载呢?这是操作系统体系所决定的,cpu只会和内存打交道。那么如何加载呢?

是linux中exec*系统接口(加载器)加载的。

请问程序是先加载还是先执行main呢?
肯定是先加载

在这里插入图片描述
虽然前4个exec系列接口没有环境变量参数,但是子进程照样还是可以拿到系统默认的环境变量。因为地址空间有一块区域,存放命令行参数环境变量。

2.4.6execvp

int execvpe(const char *file, char *const argv[],char *const envp[]);

这个函数就不再演示了,就是增加了自动去环境变量寻找程序路径。

2.5总结

上面共学了6个进程替换函数,其实还有一个,这一个才是真正执行程序替换。

在这里插入图片描述
这个函数属于系统调用接口,其他exec系列接口都是对其封装,主要是为了满足不同的应用场景。

自此关于进程等待,进程替换内容结束了,这篇博文比较长。喜欢的点赞,评论,收藏+关注!!!

猜你喜欢

转载自blog.csdn.net/fight_p/article/details/132944772