• Linux系统编程——进程替换:exec 函数族


    在 Windows 平台下。我们能够通过双击运行可运行程序。让这个可运行程序成为一个进程;而在 Linux 平台。我们能够通过 ./ 运行,让一个可运行程序成为一个进程。


    可是,假设我们本来就执行着一个程序(进程),我们怎样在这个进程内部启动一个外部程序。由内核将这个外部程序读入内存,使其执行起来成为一个进程呢?这里我们通过 exec 函数族实现。


    exec 函数族。顾名思义。就是一簇函数,在 Linux 中,并不存在 exec() 函数。exec 指的是一组函数。一共同拥有 6 个:

    1. #include <unistd.h>  
    2. int execl(const char *path, const char *arg, ...);  
    3. int execlp(const char *file, const char *arg, ...);  
    4. int execle(const char *path, const char *arg, ..., char * const envp[]);  
    5. int execv(const char *path, char *const argv[]);  
    6. int execvp(const char *file, char *const argv[]);  
    7. int execve(const char *path, char *const argv[], char *const envp[]);  


    当中仅仅有 execve() 是真正意义上的系统调用,其他都是在此基础上经过包装的库函数。


    exec 函数族提供了六种在进程中启动还有一个程序的方法exec 函数族的作用是依据指定的文件名称或文件夹名找到可运行文件,并用它来代替调用进程的内容,换句话说,就是在调用进程内部运行一个可运行文件。



    进程调用一种 exec 函数时,该进程全然由新程序替换。而新程序则从其 main 函数開始运行。

    由于调用 exec 并不创建新进程,所以前后的进程 ID (当然还有父进程号、进程组号、当前工作文件夹……)并未改变。exec 仅仅是用还有一个新程序替换了当前进程的正文、数据、堆和栈段(进程替换)。


    exec 函数族的 6 个函数看起来似乎非常复杂,但实际上不管是作用还是使用方法都非常相似,仅仅有非常微小的区别。




    l(list):參数地址列表,以空指针结尾。


    v(vector):存有各參数地址的指针数组的地址。

    p(path):按 PATH 环境变量指定的文件夹搜索可运行文件。


    e(environment):存有环境变量字符串地址的指针数组的地址。


    exec 函数族装入并执行可执行程序 path/file,并将參数 arg0( arg1, arg2, argv[], envp[] ) 传递给此程序。


    exec 函数族与一般的函数不同,exec 函数族中的函数运行成功后不会返回,并且。exec 函数族以下的代码运行不到仅仅有调用失败了,它们才会返回 -1,失败后从原程序的调用点接着往下运行。


    excel代码:

    #include <stdio.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
    	printf("before exec
    
    ");
    	
    	/* /bin/ls:外部程序,这里是/bin文件夹的 ls 可运行程序,必须带上路径(相对或绝对)
    	   ls:没有意义。假设需要给这个外部程序传參,这里必需要写上字符串,至于字符串内容随意
    	   -a,-l,-h:给外部程序 ls 传的參数
    	   NULL:这个必须写上,代表给外部程序 ls 传參结束
    	*/
    	execl("/bin/ls", "ls", "-a", "-l", "-h", NULL);
    	
    	// 假设 execl() 运行成功,以下运行不到,由于当前进程已经被运行的 ls 替换了
    	perror("execl");
    	printf("after exec
    
    ");
    	
    	return 0;
    }

    执行结果:



    execv()演示样例代码:

    execv() 和 execl() 的使用方法基本是一样的,无非将列表传參,改为用指针数组

    #include <stdio.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
    	// execv() 和 execl() 的使用方法基本是一样的,无非将列表传參。改为用指针数组
    	// execl("/bin/ls", "ls", "-a", "-l", "-h", NULL);
    	
    	/* 指针数组
    	   ls:没有意义,假设需要给这个外部程序传參,这里必需要写上字符串,至于字符串内容随意
    	   -a,-l。-h:给外部程序 ls 传的參数
    	   NULL:这个必须写上。代表给外部程序 ls 传參结束
    	*/
    	char *arg[]={"ls", "-a", "-l", "-h", NULL};
    	
    	// /bin/ls:外部程序。这里是/bin文件夹的 ls 可运行程序,必须带上路径(相对或绝对)
    	// arg: 上面定义的指针数组地址
    	execv("/bin/ls", arg);
    	
    	perror("execv");
    		
    	return 0;
    }

    execlp() 或 execvp() 演示样例代码:

    execlp() 和 execl() 的差别在于,execlp() 指定的可运行程序能够不带路径名,假设不带路径名的话,会在环境变量 PATH指定的文件夹里寻找这个可运行程序,而 execl() 指定的可运行程序。必须带上路径名。

    1. #include <stdio.h>  
    2. #include <unistd.h>  
    3.   
    4. int main(int argc, char *argv[])  
    5. {  
    6.     // 第一个參数 "ls"。没有带路径名,在环境变量 PATH 里寻找这个可运行程序  
    7.     // 其他參数使用方法和 execl() 一样  
    8.     execlp("ls""ls""-a""-l""-h", NULL);  
    9.       
    10.     /* 
    11.     char *arg[]={"ls", "-a", "-l", "-h", NULL}; 
    12.     execvp("ls", arg); 
    13.     */  
    14.       
    15.     perror("execlp");  
    16.       
    17.     return 0;  
    18. }  


    execle() 或 execve() 演示样例代码:

    execle() 和 execve() 改变的是 exec 启动的程序的环境变量(仅仅会改变进程的环境变量,不会影响系统的环境变量)。其它四个函数启动的程序则使用默认系统环境变量。


    execle()演示样例代码:

    #include <stdio.h>
    #include <unistd.h>
    #include <stdlib.h> // getenv()
    
    int main(int argc, char *argv[])
    {
    	// getenv() 获取指定环境变量的值
    	printf("before exec:USER=%s, HOME=%s
    ", getenv("USER"), getenv("HOME"));
    	
    	// 指针数据
    	char *env[]={"USER=EDU", "HOME=/tmp", NULL};
    	
    	/* ./edu:外部程序,当前路径的 edu 程序,通过 gcc edu.c -o edu 编译
    		edu:这里没有意义
    		NULL:给 edu 程序传參结束
    		env:改变 edu 程序的环境变量,正确来说,让 edu 程序仅仅保留 env 的环境变量
    	 */
    	execle("./edu", "edu", NULL, env);
    	
    	/*
    	char *arg[]={"edu", NULL};		
    	execve("./edu", arg, env);	
    	*/
    	
    	perror("execle");
    	
    	return 0;
    }

    外部程序。edu.c 演示样例代码:
    #include <stdio.h>
    #include <stdlib.h>
    #include <unistd.h>
    
    int main(int argc, char *argv[])
    {
    	printf("
    in the edu fun, after exec: 
    ");
    	printf("USER=%s
    ", getenv("USER"));
    	printf("HOME=%s
    ", getenv("HOME"));
    	
    	return 0;
    }

    执行结果:





  • 相关阅读:
    WDA基础三:简单的INPUT选择,简单的TABLE显示
    WDA基础二:界面,元素介绍
    WDA基础一:激活相关服务
    docker in all
    神经网络理论与工程实战-知识积累
    信息论理论学习笔记
    机器学习数学知识积累总结
    互联网,IT,大数据,机器学习,AI知识tag云
    java web dev知识积累
    windows系统相关命令及问题排查实践
  • 原文地址:https://www.cnblogs.com/wzjhoutai/p/6991102.html
Copyright © 2020-2023  润新知