linux代码实操:exec系列函数进程实验

发布于:2024-04-26 ⋅ 阅读:(24) ⋅ 点赞:(0)
  前面我有一篇文章介绍到了使用fork()函数启动一个子进程,事实上,这是并没有太大作用的,因为子进程跟父进程都是一样的, 子进程能干的活父进程也一样能干,因此世界各地的开发者就想方设法让子进程做不一样的事情, 于是诞生了exec系列函数,这个系列函数主要是用于替换进程的执行程序, 它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段, 在执行完之后,原调用进程的内容除了进程号外,其他全部被新程序的内容替换。 另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行脚本文件。 简单来说就是覆盖进程,举个例子,A进程通过exec系列函数启动一个进程B,此时进程B会替换进程A, 进程A的内存空间、数据段、代码段等内容都将被进程B占用,然后进程A将不复存在。

 

  下面直接通过execl()实验进行讲解: 

int execl(const char *path, const char *arg, ...)

execl()函数用于执行参数path字符串所代表的文件路径(必须指定路径), 接下来是一系列可变参数,它们代表执行该文件时传递过去的 argv[0]、argv[1]… argv[n] , 最后一个参数必须用空指针NULL作为结束的标志。 

 

int main(void)
{
    int err;

    printf("this is a execl function test demo!\n\n");

    err = execl("/bin/ls", "ls", "-la", NULL);

    if (err < 0) {
        printf("execl fail!\n\n");
    }

    printf("Done!\n\n");
}

 

代码中通过execl()函数的参数列表调用了ls命令程序, 然后将第二个以后的参数当做该文件的 argv[0]、argv[1]… argv[n], 最后一个参数必须用空指针NULL作为结束的标志。 它其实就是与我们在终端上运行”ls -la”产生的结果是一样的。 

以上函数实例代码在system_programing/exec/sources/exec.c文件中, 使用如下命令即可编译测试: 

# 以下操作在 system_programing/exec 代码目录进行
# 编译X86版本程序
make
# 运行X86版本程序
./build_x86/exec_demo

# 若是想在开发板运行,可使用如下命令进行交叉编译
make ARCH=ARM
# 交叉编译生成的 armhf 架构程序在build_ARM目录下,
# 复制至开发板运行即可

程序先打印出它的第一条消息”this is a execl function test demo!”, 接着调用exec系列函数(实验中使用execl()函数), 这个函数在/bin/ls目录中搜索程序ls,然后它将会替换exec_demo本身的进程, 程序运行结果与在终端中使用以下所示的shell命令一样,如下图。 

提示 :exec系列函数是直接将当前进程给替换掉的, 当调用exec系列函数后,当前进程将不会再继续执行, 所以示例程序中的“ Done! ”将不被输出,因为当前进程已经被替换了,一般情况下, exec系列函数函数是不会返回的,除非发生了错误。出现错误时, exec系列函数将返回-1,并且会设置错误变量errno。

因此我们可以通过调用fork()复制启动一个子进程,并且在子进程中调用exec系列函数替换子进程, 这样把fork()和exec系列函数结合在一起使用就是创建一个新进程所需要的一切了。 

 exec族的其它函数

exec族实际包含有 6 个不同的 exec 函数,它们功能一样,主要是传参的形式不同, 函数原型分别如下:

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[])

这些函数可以分为两大类,execl、execlp和execle传递给子程序的参数个数是可变的, 如“ls -la”示例中,“-la”为子程序“ls”的参数。 execv、execvp和execve通过数组去装载子程序的参数,无论那种形式,参数都以一个空指针NULL结束,

总结来说,可以通过它们的后缀来区分他们的作用:

  • 名称包含 l 字母的函数(execl、execlp和execle)接收参数列表“list”作为调用程序的参数。

  • 名称包含 p 字母的函数(execvp 和 execlp)可接受一个程序名作为参数, 它会在当前的执行路径和环境变量“PATH”中搜索并执行这个程序(即可使用相对路径); 名字不包含p字母的函数在调用时必须指定程序的完整路径(即要求绝对路径)。

  • 名称包含 v 字母的函数(execv、execvp 和 execve)的子程序参数通过一个数组“vector”装载。

  • 名称包含 e 字母的函数(execve 和 execle)比其它函数多接收一个指明环境变量列表的参数, 并且可以通过参数envp传递字符串数组作为新程序的环境变量, 这个envp参数的格式应为一个以 NULL 指针作为结束标记的字符串数组, 每个字符串应该表示为“environment = virables”的形式。

 

 


网站公告

今日签到

点亮在社区的每一天
去签到