Linux下多进程编程之exec函数语法及使用实例
exec函数族
1)exec函数族说明
fork()函数用于创建一个子进程,该子进程几乎复制了父进程的全部内容,但是,这个新创建的进程如何执行呢?exec函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行的脚本文件。
在Linux中使用exec函数族主要有两种情况:
● 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用exec函数族中的任意一个函数让自己重生。
● 如果一个进程想执行另一个程序,那么它就可以调用fork()函数新建一个进程,然后调用exec函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程(这种情况非常普遍)。
2)exec函数族语法
实际上,在Linux中并没有exec()函数,而是有6个以exec开头的函数,它们之间的语法有细微差别,本书在后面会详细讲解。
表2列举了exec函数族的6个成员函数的语法。
表2 exec函数族成员函数语法
| 所需头文件 | #include <unistd.h> |
| 函数原型 | int execl(const char *path, const char *arg, ...) |
| int execv(const char *path, char *const argv[]) | |
| int execle(const char *path, const char *arg, ..., char *const envp[]) | |
| int execve(const char *path, char *const argv[], char *const envp[]) | |
| int execlp(const char *file, const char *arg, ...) | |
| int execvp(const char *file, char *const argv[]) | |
| 函数返回值 | -1:出错 |
这6个函数在函数名和使用语法的规则上都有细微的区别,下面就从可执行文件查找方式、参数传递方式及环境变量这几个方面进行比较。
● 查找方式。读者可以注意到,表2中的前4个函数的查找方式都是完整的文件目录路径,而最后两个函数(也就是以p结尾的两个函数)可以只给出文件名,系统就会自动按照环境变量“$PATH”所指定的路径进行查找。
● 参数传递方式。exec函数族的参数传递有两种方式:一种是逐个列举的方式,而另一种则是将所有参数整体构造指针数组传递。在这里是以函数名的第5位字母来区分的,字母为“l”(list)的表示逐个列举参数的方式,其语法为const char *arg;字母为“v”(vertor)的表示将所有参数整体构造指针数组传递,其语法为char *const argv[]。读者可以观察execl()、execle()、execlp()的语法与execv()、execve()、execvp()的区别,它们的具体用法在后面的实例讲解中会具体说明。
这里的参数实际上就是用户在使用这个可执行文件时所需的全部命令选项字符串(包括该可执行程序命令本身)。要注意的是,这些参数必须以NULL结束。
● 环境变量。exec函数族可以默认系统的环境变量,也可以传入指定的环境变量。这里以“e”(environment)结尾的两个函数execle()和execve()就可以在envp[]中指定当前进程所使用的环境变量。
表3再对这6个函数中的函数名和对应语法做了一个小结,主要指出了函数名中每一位所表明的含义,希望读者结合此表加以记忆。
表3 exec函数名对应含义
| 前4位 | 统一为:exec | |
| 第5位 | l:参数传递为逐个列举方式 | execl、execle、execlp |
| v:参数传递为构造指针数组方式 | execv、execve、execvp | |
| 第6位 | e:可传递新进程环境变量 | execle、execve |
| p:可执行文件查找方式为文件名 | execlp、execvp | |
事实上,这6个函数中真正的系统调用只有execve(),其他5个都是库函数,它们最终都会调用execve()这个系统调用。在使用exec函数族时,一定要加上错误判断语句。exec很容易执行失败,其中最常见的原因有:
● 找不到文件或路径,此时errno被设置为ENOENT。
● 数组argv和envp忘记用NULL结束,此时errno被设置为EFAUL。
● 没有对应可执行文件的运行权限,此时errno被设置为EACCES。
3)exec使用实例
下面的第一个示例说明了如何使用文件名的方式来查找可执行文件,同时使用参数列表的方式。这里用的函数是execlp()。
/* execlp.c */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
if (fork() == 0)
{
/* 调用execlp()函数,这里相当于调用了“ps –ef”命令 */
if ((ret = execlp("ps", "ps", "-ef", NULL)) < 0)
{
printf("Execlp error\n");
}
}
}
在该程序中,首先使用fork()函数创建一个子进程,然后在子进程中使用execlp()函数。读者可以看到,这里的参数列表列出了在shell中使用的命令名和选项,并且当使用文件名进行查找时,系统会在默认的环境变量PATH中寻找该可执行文件。读者可将编译后的结果下载到目标板上,运行结果如下:
$ ./execlp
PID TTY Uid Size State Command
1 root 1832 S init
2 root 0 S [keventd]
3 root 0 S [ksoftirqd_CPU0]
4 root 0 S [kswapd]
5 root 0 S [bdflush]
6 root 0 S [kupdated]
7 root 0 S [mtdblockd]
8 root 0 S [khubd]
35 root 2104 S /bin/bash /usr/etc/rc.local
36 root 2324 S /bin/bash
41 root 1364 S /sbin/inetd
53 root 14260 S /Qtopia/qtopia-free-1.7.0/bin/qpe -qws
54 root 11672 S quicklauncher
65 root 0 S [usb-storage-0]
66 root 0 S [scsi_eh_0]
83 root 2020 R ps -ef
$ env
…
PATH=/Qtopia/qtopia-free-1.7.0/bin:/usr/bin:/bin:/usr/sbin:/sbin
…
此程序的运行结果与在shell中直接输入命令“ps -ef”是一样的,当然,在不同系统的不同时刻可能会有不同的结果。
接下来的示例使用完整的文件目录来查找对应的可执行文件。注意,目录必须以“/”开头,否则将其视为文件名。
/* execl.c */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
if (fork() == 0)
{
/* 调用execl()函数,注意这里要给出ps程序所在的完整路径 */
if (execl("/bin/ps","ps","-ef",NULL) < 0)
{
printf("Execl error\n");
}
}
}
同样将代码下载到目标板上运行,运行结果同上例。
下面的示例利用execle()函数将环境变量添加到新建的子进程中,这里的“env”是查看当前进程环境变量的命令,代码如下:
/* execle.c */
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
/* 命令参数列表,必须以NULL结尾 */
char *envp[]={"PATH=/tmp","USER=david", NULL};
if (fork() == 0)
{
/* 调用execle()函数,注意这里也要指出env的完整路径 */
if (execle("/usr/bin/env", "env", NULL, envp) < 0)
{
printf("Execle error\n");
}
}
}
下载到目标板后的运行结果如下:
$ ./execle
PATH=/tmp
USER=sunq
最后一个示例使用execve()函数,通过构造指针数组的方式来传递参数,注意参数列表一定要以NULL作为结尾标识符。其代码如下:
#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>
int main()
{
/* 命令参数列表,必须以NULL结尾 */
char *arg[] = {"env", NULL};
char *envp[] = {"PATH=/tmp", "USER=david", NULL};
if (fork() == 0)
{
if (execve("/usr/bin/env", arg, envp) < 0)
{
printf("Execve error\n");
}
}
}
下载到目标板后的运行结果如下:
$ ./execve
PATH=/tmp
USER=david
本文选自华清远见嵌入式培训教材《从实践中学嵌入式Linux应用程序开发》
文章来源:华清远见企业学院,原文地址:http://www.farsight.com.cn/news/emb188.htm
Linux下多进程编程之exec函数语法及使用实例的更多相关文章
- 深入浅出--UNIX多进程编程之fork()函数
0前言 上周都在看都在学习unix环境高级编程的第八章--进程控制.也就是这一章中.让我理解了unix中一些进程的原理.以下我就主要依照进程中最重要的三个函数来进行解说.让大家通过阅读这一篇文章彻底明 ...
- 多进程编程之system()函数
1.system函数: 使用函数system,在程序中执行一个shell命令字符串很方便.它是一个和操作系统紧密相关的函数,用户可以使用它在自己的程序中调用系统提供的各种命令,执行系统的命令行,其实也 ...
- Linux/Unix C编程之的perror函数,strerror函数,errno
#include <stdio.h> // void perror(const char *msg); #include <string.h> // char *strerro ...
- linux下多进程的调试
linux下多进程的调试: (1)follow-fork-mode set follow-fork-mode [parent | child] ---- fork之后选择调试父进 ...
- Python 多进程编程之multiprocessing--Pool
Python 多进程编程之multiprocessing--Pool ----当需要创建的子进程数量不多的时候,可以直接利用multiprocessing 中的Process 动态生成多个进程, -- ...
- Python 多进程编程之multiprocessing--Process
Python 多进程编程之multiprocessing 1,Process 跨平台的进程创建模块(multiprocessing), 支持跨平台:windowx/linux 创建和启动 创 ...
- linux c语言 fork() 和 exec 函数的简介和用法
linux c语言 fork() 和 exec 函数的简介和用法 假如我们在编写1个c程序时想调用1个shell脚本或者执行1段 bash shell命令, 应该如何实现呢? 其实在<std ...
- unix下网络编程之I/O复用(三)
poll函数 在上文unix下网络编程之I/O复用(二)中已经介绍了select函数的相关使用,本文将介绍另一个常用的I/O复用函数poll.poll提供的功能与select类似,不过在处理流设备时, ...
- linux下c程序调用reboot函数实现直接重启【转】
转自:http://www.blog.chinaunix.net/uid-20564848-id-73878.html linux下c程序调用reboot函数实现直接重启 当然你也可以直接调用syst ...
随机推荐
- 攻城狮在路上(壹) Hibernate(二)--- 第一个hibernate程序
1.直接通过JDBC API持久化实体域对象: A.java.sql常用接口和类: DriverManager:驱动程序管理器,负责创建数据库连接. Connection:代表数据库连接. State ...
- windows下Tomcat配置多实例
详情参见tomcat安装目录下RUNNING.txt中Advanced Configuration - Multiple Tomcat Instances部分. 问题源于下面这段tomcat官方文档的 ...
- Linux环境下使用C/C++编写CGI(httpd)
step1下载: ftp://ftp.gnu.org/gnu/cgicc/ step2: tar xzf cgicc-X.X.X.tar.gz(用最新版本) cd cgicc-X.X.X ./conf ...
- JqueryEasyUI 解决IE下加载时页面错乱的问题 分类: JavaScript JqueryEasyUI 2014-09-20 09:50 545人阅读 评论(1) 收藏
问题描述: 一直觉得jqueryeasyui在IE下的渲染效果不大好,尤其刚进入页面时的加载,页面会出现布局错乱,虽然是一闪而过,但是给用户的体验不好: 可以通过在页面onload时,增加一个遮罩层, ...
- html5 方框内的小球
html5 方框内的小球 版本一 <!DOCTYPE html> <html> <head lang="en"> <meta charse ...
- TCP通讯程序设计
TCP通讯程序设计 这里主要包含客户机和服务器的编程. 一.编程模型函数化 使用函数说明:socket的理解 服务器: 创建socket使用函数----->socket 绑定地址使用函数---- ...
- easyui tree折叠
标签 <div id="buildDiv" data-options="region:'center'" title="楼栋权限" s ...
- snakeyaml - Documentation.wiki
SnakeYAML Documentation This documentation is very brief and incomplete. Feel free to fix or improve ...
- JavaScript设计模式——状态模式
状态和行为: 所谓对象的状态,通常指的就是对象实例的属性的值:而行为指的就是对象的功能,再具体点说,行为大多可以对应到方法上. 状态模式的功能就是分离状态的行为,通过维护状态的变化,来调用不同状态对应 ...
- DOM--2 创建可重用的对象
对象中包含的 分类(内置对象: 注意这些都是function:除了Function对象,实例都是object) Function对象 Function实例function 构造函数的function ...