进程的替换(exec)

1. 函数族 

exec函数族,是由六个exec函数组成的。

  1. exec函数族提供了六种在进程中启动另一个程序的方法。
  2. exec函数族可以根据指定的文件名或目录名找到可执行文件。
  3. 调用exec函数的进程并不创建新的进程,故调用exec前后,进程的进程号并不会改变,其执行的程序完全由新的程序替换,而新程序则从其main函数开始执行。

exec函数族取代调用进程的数据段、代码段和堆栈段

注意:一个进程调用exec后,除了进程ID,进程还保留了下列特征不变:父进程号、进程组号、控制终端、根目录、当前工作目录、进程信号屏蔽集、未处理信号 

2. exec函数

需要的头文件

#include <unistd.h>

函数结构: 

  1. int execl(const char *path, const char *arg, .../* (char *) NULL */);
  2. int execlp(const char *file, const char *arg, .../* (char *) NULL */);
  3. int execle(const char *path, const char *arg, .../*, (char *) NULL*/, cha r * const envp[ ] );
  4. int execv(const char *path, char *const argv[ ]);
  5. int execvp(const char *file, char *const argv[ ]);
  6. int execve(const char *file, char *const argv[ ], char *const envp[ ]);

注意:6个exec函数中只有execve是真正意义的系统调用(内核提供的接口),其它函数都是在此基础上经过封装的库函数

3. 后缀的意义

  • l (list):参数地址列表,以空指针结尾;参数地址列表:char *file(), char *arg1, ... char *argn  NULL 
  • v (vector):存有各参数地址的指针数组的地址;使用时先构造一个指针数组,指针数组存在各参数的地址,然后将该指针数组地址作为函数的参数
  • p (path):按PATH环境变量指定目录搜索可执行文件;以p结尾的exec函数取文件名作为参数,当指定filename作为参数时,若filename中包含/,则将其视为路径名,并直接到指定的路径中执行程序。
  • e (environment):存有环境变量字符串地址的指针数组的地址,execle和execve改变的是exec启动的程序的环境变量(新的环境变量完全由environment指定),其它四个函数启动的程序则使用默认系统环境变量。

注意:exec函数族和一般的函数不同,exec函数族中的函数执行成功后不会返回。只有调用失败后,他们才会返回-1。失败后从原程序的调用点接着往下执行,在平时的编程中,如果用到了exec函数族,一定要记得加上错误判断语句。

代码展示:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/wait.h>

int main(int argc, char const *argv[])
{
    pid_t pid;
    if((pid = fork()) < 0)
    {
        perror("fail to fork");
        exit(1);
    }
    else if(pid > 0) //父进程
    {
        printf("This is parent process\n");

        wait(NULL);
        printf("The child process has quited\n");
    }
    else //子进程
    {
        printf("This is child process\n");

        //调用exec函数族中的函数,执行其他命令或者程序
        //查看命令的路径:whereis 命令或者which 命令
        
        //***************exec函数族调用shell命令******************
        //不带p的函数,命令的路径一定要用绝对路径
#if 0
        if(execl("/bin/ls", "ls", "-l", NULL) == -1)
        {
            perror("fail to execl");
            exit(1);
        }
#endif     

        //带p的函数,第一个参数既可以是相对路径,也可以是绝对路径
#if 0
        if(execlp("ls", "ls", "-l", NULL) == -1)
        {
            perror("fail to execlp");
            exit(1);
        }
#endif

        //带v的函数需要使用指针数组来传递
#if 0 
        char *str[] = {"ls", "-l", NULL};
        if(execv("/bin/ls", str) == -1)
        {
            perror("fail to execv");
            exit(1);
        }
#endif
        //***************exec函数族调用可执行文件******************
#if 0       
        if(execlp("./hello", "./hello", NULL) == -1)
        {
            perror("fail to execlp");
            exit(1);
        }
#endif

#if 0
        if(execl("./hello", "./hello", NULL) == -1)
        {
            perror("fail to execl");
            exit(1);
        }
#endif

        //***************exec函数族调用shell脚本******************
#if 1        
        if(execlp("./myshell.sh", "./myshell.sh", NULL) == -1)
        {
            perror("fail to execl");
            exit(1);
        }
#endif
        //exec函数族取代调用进程的数据段、代码段和堆栈段
        //所以当exec函数执行完毕后,当前进程就结束了,所以原本进程中的代码不会再执行
        printf("hello world\n");
    }

    return 0;
}
  • 6
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值