进程替换 --- exec

在 Linux 中,exec 指的是一组函数,一共有 6 个。其中只有 execve() 是真正意义上的系统调用,其它都是在此基础上经过包装的库函数。当进程调用一种 exec 函数时,该进程完全由新程序替换,而新程序则从其 main 函数开始执行。因为调用 exec 并不创建新进程,所以前后的进程 ID (当然还有父进程号、进程组号、当前工作目录……)并未改变。exec 只是用另一个新程序替换了当前进程的正文、数据、堆和栈段(进程替换)。

区别

/* 完整的路径加文件名,
*  使用列表传参的方式 */
int execl(const char *path, const char *arg, ...); 
/* 完整的路径加文件名,
*  使用字符串数组传参(argv) */
int execv(const char *path, char *const argv[]);   

/* 可以直接使用可执行文件的文件名,不用带路径,程序会在环境变量 PATH 里查找该执行程序。
*  使用列表传参 */
int execlp(const char *file, const char *arg, ...);  
/* 可以直接使用可执行文件的文件名,不用带路径,程序会在环境变量 PATH 里查找该执行程序。
*  使用字符串数组传参(argv) */
int execvp(const char *file, char *const argv[]);  

/* 完整的路径加文件名,
*  使用列表传参的方式。
*  可使用字符串数组 envp 改变替换程序的环境变量,正确来说,让替换程序只保留 envp 的环境变量 */
int execle(const char *path, const char *arg, ..., char * const envp[]);  
/* 完整的路径加文件名,
*  使用字符串数组传参(argv)
*  可使用字符串数组 envp 改变替换程序的环境变量,正确来说,让替换程序只保留 envp 的环境变量 */
int execve(const char *path, char *const argv[], char *const envp[]);

execl、execv、execlp和execvp代码

#include<stdio.h>
#include<unistd.h>

int main()
{
    printf("进程替换之前.......\n");
    sleep(5);

    /* 可执行程序的全路径,参数列表传参,以 NULL 结束传参 */
    //execl("/bin/ls","ls","-al",NULL);

    /* 可执行程序的全路径,字符串数组传参,以 NULL 结束传参 */
    //char* argv[]={"ls","-al",NULL};
    //execv("/bin/ls",argv);

    /* 只需可执行程序的文件名,参数列表传参,以 NULL 结束传参 */
    //execlp("ls","ls","-al",NULL);

    /* 只需可执行程序的文件名,字符串数组传参,以 NULL 结束传参 */
    char* argv[]={"ls","-al",NULL};
    execvp("ls",argv);

    /* exec 函数族与一般的函数不同,exec 函数族中的函数执行成功后不会返回,
    *  而且,exec 函数族下面的代码执行不到。
    *  只有调用失败了,它们才会返回 -1,失败后从原程序的调用点接着往下执行。 */
    perror("execl");

    return 0;
}

四种方式的执行结果均如下,可见程序确实替换为 ls ,并按照指定参数执行。

[lingyun@manjaro study]$ gcc study.cpp -o study
[lingyun@manjaro study]$ ./study
进程替换之前.......
总用量 64
drwxr-xr-x 6 lingyun lingyun  4096  8月  3 11:20 .
drwxr-xr-x 6 lingyun lingyun  4096  8月  1 20:16 ..
drwxr-xr-x 2 lingyun lingyun  4096  4月 20 09:55 include
-rw-r--r-- 1 lingyun lingyun  9509  6月 17 21:38 main.c
drwxr-xr-x 2 lingyun lingyun  4096  4月 20 09:53 res
drwxr-xr-x 2 lingyun lingyun  4096  4月 20 09:55 src
-rwxr-xr-x 1 lingyun lingyun 16696  8月  3 11:20 study
-rw-r--r-- 1 lingyun lingyun  4179  8月  3 11:19 study.cpp
drwxr-xr-x 2 lingyun lingyun  4096  7月  6 12:06 .vscode

 execle 和 execve 代码

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

/* study.cpp */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
 
int main()
{
    /* getenv() 获取指定的环境变量的值 */ 
    printf("进程替换之前:USER=%s, HOME=%s\n", getenv("USER"), getenv("HOME"));
	
    char *envp[]={"USER=LINGYUN", "HOME=/tmp", NULL};

    /* ./main是外部程序,有另外的代码编译得到
	列表传参,NULL表示给 ./main 程序传参结束
	env:改变 ./main 程序的环境变量,准确一点,是让 ./main 程序只保留 envp 的环境变量
    */
    //execle("./main", "main", NULL, envp);

    /* ./main是外部程序,有另外的代码编译得到
	字符串数组传参,NULL表示给 ./main 程序传参结束
	env:改变 ./main 程序的环境变量,准确一点,是让 ./main 程序只保留 envp 的环境变量
    */
    char* argv[] = {"main",NULL};
    execve("./main",argv,envp);
	
    perror("execle");
	
    return 0;
}
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
int main(int argc, char *argv[])
{
    printf("进程替换之后: USER=%s,HOME=%s\n",getenv("USER"),getenv("HOME"));
    return 0;
}

 执行可见,环境变量确实发生了改变。

[lingyun@manjaro study]$ gcc main.c -o main
[lingyun@manjaro study]$ gcc study.cpp -o study
[lingyun@manjaro study]$ ./study 
进程替换之前:USER=lingyun, HOME=/home/lingyun
进程替换之后: USER=LINGYUN,HOME=/tmp

exec 并没有创建新的进程

/* study.cpp */
#include<stdio.h>
#include<unistd.h>

int main()
{
    printf("进程替换之前的进程 ID: %d, 父进程 ID: %d\n",getpid(),getppid());
    sleep(5);

    execl("./main", "main", NULL);

    perror("execl");

    return 0;
}
/* main.c */
#include<stdio.h>
#include<unistd.h>

int main()
{
    printf("进程替换之前的进程 ID: %d, 父进程 ID: %d\n",getpid(),getppid());
    return 0;
}

执行可见,进程替换前后的进程 ID 和父进程 ID 都没有发生改变。

[lingyun@manjaro study]$ gcc main.c -o main
[lingyun@manjaro study]$ gcc study.cpp -o study
[lingyun@manjaro study]$ ./study 
进程替换之前的进程 ID: 6499, 父进程 ID: 2411
进程替换之前的进程 ID: 6499, 父进程 ID: 2411

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值