Linux多进程编程之exec函数族使用

1.exec函数族是什么

顾名思义,它并不只是一个函数,而是以exec开头的六个函数,并且是没有exec这个函数的(就像TCP/IP协议族不只是TCP和IP两个协议一样):

       int execl(const char *path, const char *arg, ...
                       /* (char  *) NULL */);
       int execlp(const char *file, const char *arg, ...
                       /* (char  *) NULL */);
       int execle(const char *path, const char *arg, ...
                       /*, (char *) NULL, char * const envp[] */);
       int execv(const char *path, char *const argv[]);
       int execvp(const char *file, char *const argv[]);
       int execvpe(const char *file, char *const argv[],
                       char *const envp[]);

它们的作用就是在使用fork产生多进程之后,可以将子进程的进程空间替换成我们想要执行的程序,产生一个金蝉脱壳的效果。因为很多时候我们并不想让子进程一样的执行父进程的代码,因为子进程复制了父进程的进程空间,一样的代码和变量。而使用exec函数族则可以让子进程换成其它的可执行程序。
而在exec函数族当中,如上面的代码所示,最常用的起始就是前两个函数,execl和execlp。所以下面具体讲解前两个函数的具体用法,其它函数当然也会介绍如何使用。

2.execl函数具体使用

首先我们可以先生成一个可执行程序:

//hello.c
#include <stdio.h>

int main() {
    
    
    printf("hello Ntt!\n");
    return 0;
}

然后可以在Linux下编译一下:

sudo gcc hello.c -o hello

关于execl的解读:

int execl(const char *path, const char *arg, ...
                       /* (char  *) NULL */);

第一个参数path代表的是可执行文件的路径,可以使用绝对路径或者相对路径,推荐使用绝对路径。后面的都是这个可执行文件的参数,以NULL作为结尾,这里注意,虽然我们hello程序没有其它的参数,但它本身就算参数的一部分,所以下面可见具体使用:

//excel.c
//CSDN Credic1017
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    
    
    pid_t pid = fork();
    if(pid > 0) {
    
    
        printf("I am parent process. and pid=%d, ppid=%d\n", getpid(), getppid());
        sleep(1);
    }else if(pid == 0) {
    
    
        execl("hello", "hello", NULL);
        //下面的代码不会执行
        printf("I am child process. and pid=%d, ppid=%d\n", getpid(), getppid());
    }
    return 0;
}

编译一下:

sudo gcc excel.c -o excel

并且在return 0前面再放个打印语句,子进程也不会执行该打印语句,因为它的进程空间全部被替换了,替换成了我们的hello可执行程序。
这里的话还可以调用Linux本身的程序,比如查看系统进程状态 ps aux,那么这里同理,ps所在的位置可用which查看,ps作为第一个参数,aux作为第二个参数,都是以字符数组存在的参数,最后以NULL结尾。

//excel.c
//CSDN Credic1017
#include <stdio.h>
#include <unistd.h>
#include <sys/types.h>

int main() {
    
    
    pid_t pid = fork();
    if(pid > 0) {
    
    
        printf("I am parent process. and pid=%d, ppid=%d\n", getpid(), getppid());
        sleep(1);
    }else if(pid == 0) {
    
    
        execl("/bin/ps", "ps", "aux", NULL);
        //下面的代码不会执行
        printf("I am child process. and pid=%d, ppid=%d\n", getpid(), getppid());
    }
    return 0;
}

3.execlp

int execlp(const char *file, const char *arg, ...
                       /* (char  *) NULL */);

这里只讲和execl的区别,第一个参数由path改为了file,file直接就为需要执行的可执行文件的文件名,就比如hello,像之前的path,就是要选定文件的相对路径或者绝对路径。当然ps也是直接写的,而不是像之前的/bin/ps。后面的参数还是一样的。

execlp("ps", "ps", "aux", NULL);

它也会和之前的运行结果一样,主要是他会到环境变量中去找。如果环境变量没找到则返回失败的参数。

4.exec后面不同字母所代表的含义

在这里插入图片描述
前面在execl中已经使用了l,其实就是代表参数地址以空指针结尾,使用了参数地址列表。
p的话也介绍了,其实就是在可执行程序那块会自动调用环境变量,从而可以少写点路径名。
那再看到exec后面带v的一个用法:

//声明:
int execv(const char *path, char *const argv[]);

//使用:
char *argv = {
    
    "ps", "aux", NULL};
execv("/bin/ps", argv);

那再看到exec后面带e的一个用法:
对于e结尾的解读就是存有环境变量字符串地址的指针数组的地址。

#include <unistd.h>
int execve(const char *filename, char *const argv[],
                  char *const envp[]);

//使用:
char *const envp[] = {
    
    "/home/NTT", "/home/aaa", "/home/bbb"};
char *argv = {
    
    "ps", "aux", NULL};
execve("/bin/ps", argv, envp);

所以,结合exec后面每种字母代表的含义能正确的使用exec函数族,遇事不决找男人(man)。

猜你喜欢

转载自blog.csdn.net/qq_43847153/article/details/128505326