进程体替换(exec函数族)与调用命令行(system)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/daaikuaichuan/article/details/82783330

一、进程体替换(exec函数族)

  使用函数fork()创建新的子进程后,子进程往往需要调用函数exec()以执行另一个程序。当进程调用函数exec()时,该进程执行的程序完全替换为新程序,而新程序则从其函数main()开始执行。

  与 fork 或 vfork 函数不同,exec 函数不是创建调用进程的子进程,而是创建一个新的进程取代调用进程自身。新进程会用自己的全部地址空间,覆盖调用进程的地址空间,但进程的 PID 保持不变。exec 只是用磁盘上的一个新程序替换了当前进程的正文段、数据段、堆段和栈段

  exec函数族的作用:根据指定的文件名找到可执行文件,并用它来取代调用进程的内容,换句话说,就是在调用进程内部执行一个可执行文件。这里的可执行文件既可以是二进制文件,也可以是任何Linux下可执行的脚本文件。

#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
int execlp(const char *file, const char *arg, ...);
int execle(const char *path, const char *arg, ..., char *const envp[]);
int execv(const char *path, char *const argv[]);
int execvp(const char *file, char *const argv[]);
int execve(const char *path, char *const argv[], char *const envp[]);
int fexecve(int fd, char *const argv[], char *const envp[]);
// 7 个函数返回值:若出错,返回 -1;若成功,不返回

1、execl函数

#include <unistd.h>
extern char **environ;
int execl(const char *path, const char *arg, ...);
若出错,返回 -1, 若成功,不返回

  execl()其中后缀 “l” 代表 list 也就是参数列表的意思,第一参数 path 字符指针所指向要执行的文件路径, 接下来的参数代表执行该文件时传递的参数列表:argv[0],argv[1]… 最后一个参数须用空指针NULL作结束

#include <unistd.h>
#include <iostream>
using namespace std;

int main(int argc, char *argv[])
{
    cout << "hello\n";
    // 去磁盘中加载另外一段程序,替换掉当前的正文段、数据段等。
    // 11 22 是传给./test(可执行程序)的参数。
    execl("test", "./test", "11", "22", NULL);  
    cout << "world\n";
    return 0;
}

2、execlp函数

#include <unistd.h>
int execlp(const char *file, const char *arg, ...);
若出错,返回 -1, 若成功,不返回

  execlp()会从 PATH 环境变量所指的目录中查找符合参数 file 的文件名,找到后便执行该文件,然后将第二个以后的参数当做该文件的argv[0]、argv[1]……,最后一个参数必须用空指针(NULL)作结束。

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

int main()
{
    pid_t pid;
    pid = fork();
    if (pid == 0) // 子进程启动火狐,打开一个网址
    {
     	// NULL表示参数结束
        execlp("/usr/bin/firefox", "firefox", "www.baidu.com", NULL);
    }
    else if (pid > 0)
    {
        while (1)
        {
            printf("I am parent\n");
            sleep(1);
        }
    }
    else
    {
        perror("fork");
        exit(1);
    }
    return 0;
}

  当指定 file 作为参数时,如果 file 中包含 /,则就将其视为路径名。否则就按 PATH 环境变量,在它所指定的各目录中搜索可执行文件。这也就是 execlp 和 execl 的区别了。

二、调用命令行(system)

#include <stdlib.h>
int system(const char *command);

1、函数功能与参数解析

  linux系统中可以使用函数system()函数调用shell命令。
  system()函数执行 command 参数表示的命令行,并返回命令进程的终止状态。若 command 参数是一个空指针 (NULL),则仅当命令处理程序可用时,system 返回非 0 值,这一特征可以确定在一个给定的操作系统上是否支持 system 函数。在 UNIX 中,system 总是可用的。

2、函数详解

  因为 system 在其实现中调用了 fork、exec 和 waitpid,因此有 3 种返回值。

  • fork 失败或者 waitpid 返回除 EINTR 之外的出错,则 system 返回 -1,并且设置 errno以指示错误类型。
  • 如果 exec 失败(表示不能执行 shell),则其返回值如同 shell 执行了 exit (127) 一样。
  • 如果所有 3 个函数(fork、exec 和 waitpid)都成功,那么 system 的返回值是 shell 的终止状态,其格式已在 waitpid 中说明。
#include <stdio.h>
#include <stdlib.h>
 
int main(void)
{
    int status;
    // 若 command 参数是一个空指针 (NULL),
    // 则仅当命令处理程序可用时,system 返回非 0 值。
    if ((status = system(NULL)) == -1)
        perror("system"), exit(1);
    // 通过 if (!status) 判断系统是否支持 system 函数。
    if (!status)
        printf("shell 不可用\n");
    else
    {
        // 如果成功,那么 system 的返回值是 shell 的终止状态
        // 如果将shell命令错误则,终止状态为 exit(127)
        if ((status = system("ls -l")) == -1) 
            perror("system"), exit(1);
        // WEXITSTATUS (status) 得到 exit或_exit 参数、return返回值。
        printf("WEXITSTATUS (status) = %d\n", WEXITSTATUS(status));
    }
    return 0;
}

3、system与exec的区别

  使用 system 函数而不直接使用 fork+exec 的好处是,syetem函数针对各种错误和信号都做了必要的处理,而且 system 是标准库函数,可跨平台使用。

【与exec的区别】:

1. system()和exec()都可以执行进程外的命令,system是在原进程上开辟了一个新的进程,但是exec是用新进程(命令)覆盖了原有的进程

2. system()和exec()都有能产生返回值,system的返回值并不影响原有进程,但是exec的返回值影响了原进程

参考:https://blog.csdn.net/qq_29350001/article/details/70837744

猜你喜欢

转载自blog.csdn.net/daaikuaichuan/article/details/82783330