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

news2024/12/29 10:36:06

进程等待,进程替换

  • 1.进程等待
    • 1.1进程等待必要性
    • 1.2进程等待的方法
      • 1.2.1wait方法
      • 1.2.2waitpid方法
      • 1.2.3通过宏得到退出码
      • 1.2.4 阻塞vs非阻塞
  • 2.进程替换
    • 2.1进程替换的目的
    • 2.2execl替换函数
    • 2.3理解原理
    • 2.4其他替换接口
      • 2.4.1execl
      • 2.4.2execlp
      • 2.4.3execv
      • 2.4.4execvp
      • 2.4.5 execle
      • 2.4.6execvp
    • 2.5总结

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

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系列接口都是对其封装,主要是为了满足不同的应用场景。

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1036077.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

什么是JavaScript中的IIFE(Immediately Invoked Function Expression)?它的作用是什么?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ JavaScript中的IIFE⭐ 示例⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们…

C++中实现一些特殊的类|设计模式

1.设计一个类 不能被拷贝 拷贝只会发生在两个场景中&#xff1a;拷贝构造以及赋值运算符重载。想要让一个类禁止拷贝&#xff0c;只需要该类不能调用拷贝构造和赋值运算符重载 c98中 将拷贝构造与赋值运算符重载只声明不定义&#xff0c;不定义是因为该函数根本不会调用&#x…

基于springboot+vue的校园外卖服务系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战 主要内容&#xff1a;毕业设计(Javaweb项目|小程序等)、简历模板、学习资料、面试题库、技术咨询 文末联系获取 项目介绍…

静态路由与默认路由配置

实验原理&#xff1a; 路由分类 &#xff08;1&#xff09;根据目的网络的不同&#xff0c;路由可以划分为&#xff1a; 特定网络路由&#xff1a;目的网络为目的主机所在网络的IP地址&#xff0c;其子网掩码表示的前缀长度为32位&#xff08;对于IPv4地址&#xff09;&…

分布式搜索引擎01

1.初识elasticsearch 1.1.了解ES 1.1.1.elasticsearch的作用 elasticsearch是一款非常强大的开源搜索引擎,具备非常多强大功能,可以帮助我们从海量数据中快速找到需要的内容 例如: 在GitHub搜索代码 在电商网站搜索商品 在百度搜索答案 在打车软件搜索附近的车 1.1.2.ELK…

程序员的快乐如此简单

最近在GitHub上发起了一个关于Beego框架的小插件的开源仓库&#xff0c;这一举动虽然看似微小&#xff0c;但其中的快乐和意义却是无法用言语表达的。 Beego是一个开源的Go语言Web框架&#xff0c;它采用了MVC架构模式&#xff0c;并集成了很多常用的功能和中间件。小插件是指…

Linux chmod命令——修改权限信息

我们可以使用chmod命令&#xff0c;修改文件、文件夹的权限信息。注意&#xff0c;只有文件、文件夹的所属用户或root用户可以修改。 chmod [-R] 权限 文件或文件夹 -R&#xff0c;对文件夹内的全部内容应用同样的操作 例如&#xff1a; chmod urwx,grx,ox hello.txt &…

工业余能资源评价方法 标准学习

声明 本文是学习GB-T 1028-2018 工业余能资源评价方法. 而整理的学习笔记,分享出来希望更多人受益,如果存在侵权请及时联系我们 1 范围 本标准界定了工业余能相关术语&#xff0c;规定了工业余能的分类和评价方法。 本标准适用于工业余能资源的评价。 2 术语和定义 下列术…

oracle执行计划中,同一条语句块,在不同情况下执行计划不一样问题。子查询,union 导致索引失效。

场景&#xff1a; 需要获取部分数据集(视图)的业务时间最大值&#xff0c;希望只通过一条语句获取多个的最大值。 则使用select (视图1业务时间最大值),(视图2业务时间最大值),(视图3业务时间最大值) from dual 程序执行过程中&#xff0c;发现语句执行较慢&#xff0c;则进行s…

描述符——配置描述符

描述符定义 描述符实现 /*** brief USB configuration descriptor.*/ typedef struct __attribute__ ((packed)) {uint8_t bLength ; /**< Size of this descriptor in bytes. */uint8_t bDescriptorType ; /**< CONFIGURATION Descriptor Type. */ui…

使用ElementUI完成登入注册的跨域请求,结合vue-cli搭建的SPA项目,减少冗余代码提升开发效率

目录 一、跨域的概述 ( 1 ) 讲述 ( 2 ) 特点 如何跨域: 二、ElementUI ( 1 ) 导入 ( 2 ) 搭建 ( 3 ) 页面 三、数据交互 ( 1 ) 安装相关模块 安装模块 引用模块 ( 2 ) axios的get请求 ( 3 ) axios的post请求 四、注册功能 带来的收获 一、跨域的概述 …

安卓实现网格布局的效果

文章目录 页面子项布局 Activity适配器 运行结果其他文章 页面 RecyclerView是Android开发中常用的列表控件之一&#xff0c;可以用于展示大量数据以及实现各种布局效果。本文章使用RecyclerView的GridLayoutManager来实现网格布局&#xff0c;显示指定列数。 首先&#xff0c…

25. 图论 - 路径和算法

文章目录 拓展:顶点和边的互换最短路径问题Dijkstra算法Hi, 你好。我是茶桁。 在充分了解图的概念,构成以及种类之后,我们要开始进入稍微有点难度的部分了。这节课,咱们来了解一下路径和Dijkstra算法。 拓展:顶点和边的互换 在这节课正式开始之前,我们对上一节课稍微扩…

Java笔记:认识运行时数据区

1. 运行时数据区概述 1.1 JVM运行时数据区规范 JVM虚拟机组成&#xff1a;方法区(类信息)、堆(伊甸园、老年代、永久代:new的对象等)、虚拟机栈、程序计数器、本地方法栈1.方法区和堆是内存共享的 2.虚拟机栈、本地方法栈、程序计数器是内存不共享的3.方法区&#xff1a;类信息…

描述符——接口描述符

描述符定义 描述符实现 /*** brief USB interface descriptor.*/ typedef struct __attribute__ ((packed)) {uint8_t bLength ; /**< Size of this descriptor in bytes. */uint8_t bDescriptorType ; /**< INTERFACE Descriptor Type. */uint8_t bIn…

MySQL数据库——索引(3)-索引语法(创建索引、查看索引、删除索引、案例演示),SQL性能分析(SQL执行频率,慢查询日志)

目录 索引语法 创建索引 查看索引 删除索引 案例演示 SQL性能分析 SQL执行频率 慢查询日志 索引语法 创建索引 CREATE [ UNIQUE | FULLTEXT ] INDEX index_name ON table_name (index_col_name,... ) ; 查看索引 SHOW INDEX FROM table_name ; 删除索引 DROP INDEX …

AD拼板技巧

AD拼板设置 如图&#xff0c;有一个需要拼板的PCB&#xff0c;想要在生产是拼接生产&#xff0c;节省材料。 操作如下&#xff1a; 1、全选如下&#xff0c;按复制CtrlC。 2、把输入法调整至英文&#xff0c;按快捷键E&#xff08;先&#xff09;&#xff0c; A&#xff08;后…

开发工具MobaXterm(终极终端)

MobaXterm 又名 MobaXVT&#xff0c;是一款增强型终端、X 服务器和 Unix 命令集(GNU/ Cygwin)工具箱。 常用SSH客户端介绍&#xff1a; SSH 为 Secure Shell 的缩写&#xff0c;是目前较可靠&#xff0c;专为远程登录会话和其他网络服务提供安全性的协议。利用 SSH 协议可以有…

【1993. 树上的操作】

来源&#xff1a;力扣&#xff08;LeetCode&#xff09; 描述&#xff1a; 给你一棵 n 个节点的树&#xff0c;编号从 0 到 n - 1 &#xff0c;以父节点数组 parent 的形式给出&#xff0c;其中 parent[i] 是第 i 个节点的父节点。树的根节点为 0 号节点&#xff0c;所以 par…

C++中的Template

模板的概念 建立通用的模具&#xff0c;大大提高复用性 模板不可直接使用 函数模板 函数模板语法 函数模板作用&#xff1a; 建立一个通用函数&#xff0c;其函数返回值类型和形参类型可以不具体制定&#xff0c;用一个虚拟的类型来代表。 语法&#xff1a; template&l…