• 【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 }  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

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

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

    在这里插入图片描述

    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 }    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 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 }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 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 }   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39

    在这里插入图片描述

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

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

    在这里插入图片描述

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

    在这里插入图 片描述

    1.2.3通过宏得到退出码

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

    #include
      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
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44

    在这里插入图片描述

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    在这里插入图片描述

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

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 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 }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    在这里插入图片描述

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

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26

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

    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;   
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    在这里插入图片描述

    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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在这里插入图片描述

    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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

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

      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 } 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 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  
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    被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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 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 }            
    ~
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    在这里插入图片描述
    还可以使用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
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
      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 }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22

    在这里插入图片描述
    注意,传入自定义环境变量,在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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29

    在这里插入图片描述
    如果即想要显示自定义环境变量,又想要显示系统默认的环境变量,就将指定环境变量导入到系统中,也就是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;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27

    在这里插入图片描述

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

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

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

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

    2.4.6execvp

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

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

    2.5总结

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

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

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

  • 相关阅读:
    24-25届最新计算机毕业设计大数据选题推荐 -大数据毕业设计题目参考大全
    function declared implicitly
    C++11新特性:原始(raw)字符串
    操作系统漏洞验证及加固-MS08_067漏洞利用与安全加固
    flex-shrink 解决实际问题(flex-shrink:0避免图片被压扁)
    汽车音响静音检测电路芯片D3703F,适用于汽车音响系统,采用封装形式SOP8
    C. Fibonacci Words-April Fools Day Contest 2021
    72.动态插槽名称&无渲染组件与可组合
    PHP毕业设计项目作品源码选题(10)校园新生自助报到系统毕业设计毕设作品开题报告
    leetcode竞赛:20220911周赛
  • 原文地址:https://blog.csdn.net/fight_p/article/details/132944772