Linux系统编程——进程替换:exec 函数族

在 Windows 平台下。我们能够通过双击运行可运行程序。让这个可运行程序成为一个进程;而在 Linux 平台。我们能够通过 ./ 运行,让一个可运行程序成为一个进程。

可是,假设我们本来就执行着一个程序(进程),我们怎样在这个进程内部启动一个外部程序。由内核将这个外部程序读入内存,使其执行起来成为一个进程呢?这里我们通过 exec
函数族
实现。

exec
函数族
。顾名思义。就是一簇函数,在 Linux 中,并不存在 exec() 函数。exec 指的是一组函数。一共同拥有 6 个:

[cpp] view
plain
copy

  1. #include <unistd.h>
  2. int execl(const char *path, const char *arg, ...);
  3. int execlp(const char *file, const char *arg, ...);
  4. int execle(const char *path, const char *arg, ..., char * const envp[]);
  5. int execv(const char *path, char *const argv[]);
  6. int execvp(const char *file, char *const argv[]);
  7. int execve(const char *path, char *const argv[], char *const envp[]);

当中仅仅有 execve() 是真正意义上的系统调用,其他都是在此基础上经过包装的库函数。

exec 函数族提供了六种在进程中启动还有一个程序的方法。exec 函数族的作用是依据指定的文件名称或文件夹名找到可运行文件,并用它来代替调用进程的内容,换句话说,就是在调用进程内部运行一个可运行文件。

进程调用一种 exec 函数时,该进程全然由新程序替换。而新程序则从其 main 函数開始运行。

由于调用
exec 并不创建新进程,所以前后的进程 ID (当然还有父进程号、进程组号、当前工作文件夹……)并未改变。exec 仅仅是用还有一个新程序替换了当前进程的正文、数据、堆和栈段(进程替换)。

exec
函数族
的 6 个函数看起来似乎非常复杂,但实际上不管是作用还是使用方法都非常相似,仅仅有非常微小的区别。

l(list):參数地址列表,以空指针结尾。

v(vector):存有各參数地址的指针数组的地址。

p(path):按 PATH 环境变量指定的文件夹搜索可运行文件。

e(environment):存有环境变量字符串地址的指针数组的地址。

exec 函数族装入并执行可执行程序 path/file,并将參数 arg0( arg1, arg2, argv[], envp[] ) 传递给此程序。

exec 函数族与一般的函数不同,exec 函数族中的函数运行成功后不会返回,并且。exec 函数族以下的代码运行不到。仅仅有调用失败了,它们才会返回 -1,失败后从原程序的调用点接着往下运行。

excel代码:

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

int main(int argc, char *argv[])
{
	printf("before exec\n\n");

	/* /bin/ls:外部程序,这里是/bin文件夹的 ls 可运行程序,必须带上路径(相对或绝对)
	   ls:没有意义。假设需要给这个外部程序传參,这里必需要写上字符串,至于字符串内容随意
	   -a,-l,-h:给外部程序 ls 传的參数
	   NULL:这个必须写上,代表给外部程序 ls 传參结束
	*/
	execl("/bin/ls", "ls", "-a", "-l", "-h", NULL);

	// 假设 execl() 运行成功,以下运行不到,由于当前进程已经被运行的 ls 替换了
	perror("execl");
	printf("after exec\n\n");

	return 0;
}

执行结果:

execv()演示样例代码:

execv() 和 execl() 的使用方法基本是一样的,无非将列表传參,改为用指针数组。

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

int main(int argc, char *argv[])
{
	// execv() 和 execl() 的使用方法基本是一样的,无非将列表传參。改为用指针数组
	// execl("/bin/ls", "ls", "-a", "-l", "-h", NULL);

	/* 指针数组
	   ls:没有意义,假设需要给这个外部程序传參,这里必需要写上字符串,至于字符串内容随意
	   -a,-l。-h:给外部程序 ls 传的參数
	   NULL:这个必须写上。代表给外部程序 ls 传參结束
	*/
	char *arg[]={"ls", "-a", "-l", "-h", NULL};

	// /bin/ls:外部程序。这里是/bin文件夹的 ls 可运行程序,必须带上路径(相对或绝对)
	// arg: 上面定义的指针数组地址
	execv("/bin/ls", arg);

	perror("execv");

	return 0;
}

execlp() 或 execvp() 演示样例代码:

execlp() 和 execl() 的差别在于,execlp() 指定的可运行程序能够不带路径名,假设不带路径名的话,会在环境变量 PATH指定的文件夹里寻找这个可运行程序,而 execl() 指定的可运行程序。必须带上路径名。

[cpp] view
plain
copy

  1. #include <stdio.h>
  2. #include <unistd.h>
  3. int main(int argc, char *argv[])
  4. {
  5. // 第一个參数 "ls"。没有带路径名,在环境变量 PATH 里寻找这个可运行程序
  6. // 其他參数使用方法和 execl() 一样
  7. execlp("ls", "ls", "-a", "-l", "-h", NULL);
  8. /*
  9. char *arg[]={"ls", "-a", "-l", "-h", NULL};
  10. execvp("ls", arg);
  11. */
  12. perror("execlp");
  13. return 0;
  14. }

execle() 或 execve() 演示样例代码:

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

execle()演示样例代码:

#include <stdio.h>
#include <unistd.h>
#include <stdlib.h> // getenv()

int main(int argc, char *argv[])
{
	// getenv() 获取指定环境变量的值
	printf("before exec:USER=%s, HOME=%s\n", getenv("USER"), getenv("HOME"));

	// 指针数据
	char *env[]={"USER=EDU", "HOME=/tmp", NULL};

	/* ./edu:外部程序,当前路径的 edu 程序,通过 gcc edu.c -o edu 编译
		edu:这里没有意义
		NULL:给 edu 程序传參结束
		env:改变 edu 程序的环境变量,正确来说,让 edu 程序仅仅保留 env 的环境变量
	 */
	execle("./edu", "edu", NULL, env);

	/*
	char *arg[]={"edu", NULL};
	execve("./edu", arg, env);
	*/

	perror("execle");

	return 0;
}

外部程序。edu.c 演示样例代码:

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

int main(int argc, char *argv[])
{
	printf("\nin the edu fun, after exec: \n");
	printf("USER=%s\n", getenv("USER"));
	printf("HOME=%s\n", getenv("HOME"));

	return 0;
}

执行结果:

时间: 2024-08-03 16:00:19

Linux系统编程——进程替换:exec 函数族的相关文章

Linux系统编程@进程通信(一)

进程间通信概述 需要进程通信的原因: 数据传输 资源共享 通知事件 进程控制 Linux进程间通信(IPC)发展由来 Unix进程间通信 基于System V进程间通信(System V:UNIX系统的一个分支) POSIX进程间通信(POSIX:可移植操作系统接口,为了提高UNIX环境下应用程序的可移植性.很多其他系统也支持POSIX标准(如:DEC OpenVMS和Windows).) 现在Linux使用的进程间通信方式包括: 管道(pipe).有名管道(FIFO) 信号(signal) 消

Linux多任务编程之三:exec函数族及其基础实验(转)

来源:CSDN  作者:王文松  转自:Linux公社 exec函数族 函数族说明 fork() 函数用于创建一个新的子进程,该子进程几乎复制了父进程的全部内容,但是,这个新创建的子进程如何执行呢?exec 函数族就提供了一个在进程中启动另一个程序执行的方法.它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段.代码段和堆栈 段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了.另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执 行

Linux系统编程——进程管理

引言: 在Linux的内核的五大组成模块中,进程管理模块时非常重要的一部分,它虽然不像内存管理.虚拟文件系统等模块那样复杂,也不像进程间通信模块那样条理化,但作为五大内核模块之一,进程管理对我们理解内核的运作.对于我们以后的编程非常重要.同时,作为五大组成模块中的核心模块,它与其他四个模块都有联系.下面就对进程模块进行想写的介绍,首先要了解进程及其相关的概念.其次介绍进程的创建.切换.撤销等基本操作.除此之外,还给出了Linux内核是如何对进程进行调度管理的.      一.进程及其相关概念 进

linux系统编程-进程

进程 现实生活中 在很多的场景中的事情都是同时进行的,比如开车的时候 手和脚共同来驾驶汽车,再比如唱歌跳舞也是同时进行的: 如下是一段视频,迈克杰克逊的一段视频: http://v.youku.com/v_show/id_XMzE5NjEzNjA0.html?&sid=40117&from=y1.2-1.999.6 试想:如果把唱歌和跳舞这2件事分开以此完成的话,估计就没有那么好的效果了 程序中 如下程序,来模拟"唱歌跳舞" 这件事情 11 from time impo

Linux系统编程——进程的控制:结束进程、等待进程结束

结束进程 首先,我们回顾一下 C 语言中 continue, break, return 的作用: continue: 结束本次循环 break: 跳出整个循环,或跳出 switch() 语句 return: 结束当前函数 而我们可以通过 exit() 或 _exit() 来结束当前进程. 所需头文件: #include <stdlib.h> void exit(int value); 功能: 结束调用此函数的进程. 参数: status:返回给父进程的参数(低 8 位有效),至于这个参数是多

Linux系统编程——进程和线程的区别与联系

在许多经典的操作系统教科书中,总是把进程定义为程序的执行实例,它并不执行什么, 只是维护应用程序所需的各种资源,而线程则是真正的执行实体. 为了让进程完成一定的工作,进程必须至少包含一个线程. 进程,直观点说,保存在硬盘上的程序运行以后,会在内存空间里形成一个独立的内存体,这个内存体有自己的地址空间,有自己的堆,上级挂靠单位是操作系统.操作系统会以进程为单位,分配系统资源,所以我们也说,进程是资源分配的最小单位.更多详情,请看<进程的介绍>. 线程存在与进程当中,是操作系统调度执行的最小单位.

linux系统编程--进程相关概念

程序和进程 程序:二进制文件,占用的磁盘空间,还没运行 进程:启动的程序,数据在内存中,占用系统资源(CPU,物理内存) 并行和并发 并发:不是一个时间点的概念,而是一个时间段的概念,某个时间段内处理的请求数量 并行:增加服务器或cpu对请求的处理 一个cpu把一个时间段分成若干时间碎片,每个时间碎片只能处理一个进程,交替的处理进程 pcb(进程控制块) 常见内部成员: - 进程id - 进程的状态:初始,就绪,运行,挂起,终止 - 进程切换时,需要保存和恢复一些CPU寄存器 - 描述虚拟地址空

Linux系统编程——进程的介绍

http://my.9ku.com/fuyin/daogaoo.asp?dgid=564516 http://my.9ku.com/fuyin/daogaoo.asp?dgid=564608 http://my.9ku.com/fuyin/daogaoo.asp?dgid=564687 http://my.9ku.com/fuyin/daogaoo.asp?dgid=564782 http://my.9ku.com/fuyin/daogaoo.asp?dgid=564867 http://my.

Linux系统编程之进程

前一段时间对文件I/O的基本操作基本操作做了总结,今天这里继续按照我的理解对linux系统编程的进程操作进行总结. 首先我们先理解几个概念:程序.进程.线程. 所谓程序,就是计算机指令的集合,它以文件的形式存储在磁盘上,进程是一个程序在其自身的地址空间中的一次执行活动.而线程进程内的一个执行单元,也是进程内的可调度实体.说完这个不知道大家理解了吗?反正我第一次听到这个概念以后看到的时候可以明白过后就忘记了,现在我给大家举一个例子帮助大家理解,大家都看电视剧吧,所谓程序,就是一个剧本,像什么<西游