fork和exec函数
#include<unistd.h>
pid_t fork(void);
返回:在子进程中为0,在父进程中为子进程IO,若出错则为-
fork最困难之处在于调用它一次,它却返回两次。它在调用进程(称为父进程)中返回一次,返回值是新派生进程(称为子进程)的进程ID号;在子进程中又返回一次,返回值为0.因此,返回值本身告知当前进程是子进程还是父进程。
fork在子进程返回0而不是父进程的进程ID的原因在于:任何子进程只有一个父进程,而子进程总是可以通过getppid取得父进程的进程ID。相反,父进程可以有许多子进程而且无法获取各个子进程的进程ID。如果父进程想要跟踪所有子进程的进程ID,那么它必须记录每次调用fork的返回值。
父进程中调用fork之前打开的所有描述符在fork返回之后由子进程分享。我们将看到网络服务器利用了这个特性:父进程调用accept之后调用fork。所接受的已连接套接字随后就在进程与子进程之间共享。通常情况下,子进程接着读写这个已连接套接字,父进程则关闭这个已连接套接字。
fork的两个典型用法。
(1)一个进程创建一个自身的副本,这样每个副本都可以在另一个副本执行其他任务的同时处理各自的某个操作。这是网络服务器的典型用法。
(2)一个进程想要执行另一个程序。既然创建新进程的唯一方法是调用fork,该进程于是首先调用fork创建一个自身的副本,然后其中一个副本(通常是子进程)调用exec把自身替换成新的程序。这是诸如shell之类程序的典型用法。
存放在硬盘上的可执行程序文件能够被Unix执行的唯一方法是:由一个现有进程调用六个exec函数中的某一个。exec把当前进程映像替换成新的程序文件,而且该新程序通常从main函数开始执行。进程ID并不改变。我们称调用exec的进程为调用进程,称新执行的程序为新程序。
这6个exec函数之间的区别在于:(a)待执行的程序文件是由文件名(filename)还是由路径名(pathname)指定;(b)新程序的参数是一一列出还是由一个指针数组来引用;(c)把调用进程的环境传递给新程序还是给新程序指定新的环境。
exec函数族
函数族说明
fork() 函数用于创建一个新的子进程,该子进程几乎复制了父进程的全部内容,但是,这个新创建的子进程如何执行呢?exec 函数族就提供了一个在进程中启动另一个程序执行的方法。它可以根据指定的文件名或目录名找到可执行文件,并用它来取代原调用进程的数据段、代码段和堆栈段,在执行完之后,原调用进程的内容除了进程号外,其他全部被新的进程替换了。另外,这里的可执行文件既可以是二进制文件,也可以是Linux下任何可执行的脚本文件。
在 Linux 中使用exec函数族主要有两种情况:
● 当进程认为自己不能再为系统和用户做出任何贡献时,就可以调用 exec 函数族中的任意一个函数让自己重生。
● 如果一个进程想执行另一个程序,那么它就可以调用 fork() 函数新建一个进程,然后调用 exec 函数族中的任意一个函数,这样看起来就像通过执行应用程序而产生了一个新进程(这种情况非常普遍)。
函数族语法
实际上,在Linux中并没有exec()函数,而是由6个以 exec 开头的函数,它们之间的语法有细微差别。下表列出了 exec 函数族的6个成员函数的语法:
这些函数只有在出错时才返回到调用者,否则,控制将被传递给新程序的起始点,通常就是main函数。


这6个函数在函数名和使用语法的规则上都有细微的区别,下面就从可执行文件查找方式、参数传递方式和环境变量这几个方面进行比较。
● 查找方式:表1中的前4个函数的查找方式都是完整的文件目录路径,而最后两个函数(也就是以 p 结尾的两个函数)可以只给出文件名,系统就会自动按照环境变量“$PATH” 所指定的路径进行查找。
● 参数传递方式:exec函数族的参数传递有两种:一种是逐个列举的方式,而另一种则是将所有参数整体构造指针数组传递。在这里是以函数名的第5位字母来区分的,字母为 "l"(list)的表示逐个列举参数的方式,其语法为const char *arg;字母为“v”(vector)的表示将所有参数整体构造指针数组传递,其语法为 char *const argv[]。这里的参数实际上就是用户在使用这个可执行文件时所需的全部命令选项字符串(包括该可执行程序命令本身)。要注意的是,这些参数必须以NULL结束。
● 环境变量: exec函数族可以默认系统的环境变量,也可以传入指定的环境变量。这里以 “e”(environment)结尾的两个函数 execle()和 execve()就可以在 envp[]中指定当前进程所使用的环境变量。
表2再对这6个函数中的函数名和对应语法做了一个小结,主要指出了函数名中每一位对应所表明的含义,以此表加以记住这6个函数。
事实上,这6个函数中真正的系统调用只有execve(),其他5个都是库函数,它们最终都会调用execve()这个系统调用。在使用exec函数族时,一定要加上错误判断语句。exec 很容易执行失败,其中最常见的原因有:
① 找不到文件或路径,此时 errno 被设置为 ENOENT。
② 数组argv 和envp 忘记用NULL结束,此时,errno被设置为 EFAUL。
③ 没有对应可执行文件的运行权限,此时 errno 被设置为EACCES。
基础实验
实验1
本实验是为了说明如何使用文件名来查找可执行文件,同时使用参数列表的方式。这里用的函数是 execlp()。程序代码如下:
在该程序中,首先使用 fork()函数创建一个子进程,然后在子进程中使用 execlp()函数。可以看到,这里的参数列表列出了在 shell 中使用的命令名和选项,并且当使用文件名进行查找时,系统会在默认的环境变量PATH中寻找该可执行文件。
使用命令:gcc execlp.c -o execlp编译后,然后再执行,结果如下图:
使用env命令,可以查看到环境变量的路径名
此程序的执行结果与在shell中直接输入命令“ps -ef”是一样的,当然,在不同系统的不同时刻可能会有不同的结果。
实验2
本实验实现的功能和实验1的一样,不同的是使用的函数不同。本实验将使用完整的文件目录来查找对应的可执行文件。注意,目录必须以“/”开头,否则将其视为文件名。程序代码如下:
编写保存源文件,然后使用命令:gcc execl.c -o execl编译,接着执行命令:./execl,可以看到实验结果和实验1一样
实验3
本实验是利用execle()函数将环境变量添加到新建的子进程中,这里的“env”是查看当前进程环境变量的命令,实验代码如下:
编写保存源文件后,使用命令:gcc execle.c -o execle,再执行命令:./execle,执行结果如下图
实验4
本实验实现功能和实验3一样,不同的是使用的execve()函数,通过构造指针数组的方式来传递参数,注意参数列表一定要以NULL作为结尾标识符,实验代码如下:
编写保存源文件,使用命令:gcc execve.c -o execve,再执行命令:./execve,结果如下:
fork和exec函数的更多相关文章
- linux c语言 fork() 和 exec 函数的简介和用法
linux c语言 fork() 和 exec 函数的简介和用法 假如我们在编写1个c程序时想调用1个shell脚本或者执行1段 bash shell命令, 应该如何实现呢? 其实在<std ...
- linux进程之fork 和 exec函数
---恢复内容开始--- fork函数 该函数是unix中派生新进程的唯一方法. #include <unistd.h> pid_t fork(void); 返回: (调用它一次, 它 ...
- 从0开始自己用C语言写个shell__01_整体的框架以及fork和exec族函数的理解
最近才忙完了一个操作系统的作业,让我们用C语言实现一个Shell.总的来说,其实就是让我们 对系统调用有比较深的了解. 首先 介绍一下我的Shell 所实现的功能.1.运行可执行程序 即输入某个 标志 ...
- 【转】Linux下Fork与Exec使用
Linux下Fork与Exec使用 转自 Linux下Fork与Exec使用 一.引言 对于没有接触过Unix/Linux操作系统的人来说,fork是最难理解的概念之一:它执行一次却返回两个值.for ...
- Linux下多进程编程之exec函数语法及使用实例
exec函数族 1)exec函数族说明 fork()函数用于创建一个子进程,该子进程几乎复制了父进程的全部内容,但是,这个新创建的进程如何执行呢?exec函数族就提供了一个在进程中启动另一个程序执行的 ...
- 程序清单 8-8 exec函数实例,a.out是程序8-9产生的可执行程序
/* ============================================================================ Name : test.c Author ...
- fork和exec一起使用
先预览一下工程的目录树: 实现的功能:master进程启动slave进程. 看看Makefile内容: all: master.out slave.out master.out: master.cpp ...
- 进程控制之exec函数
用fork函数创建子进程后,子进程往往要调用一种exec函数以执行另一个程序.当进程调用一种exec函数时,该进程执行的程序完全替换为新程序,而新程序则从其main函数开始执行.因为调用exec并不创 ...
- linux exec函数家族
1.exec家族一共有六个函数,分别是: (1)int execl(const char *path, const char *arg, ......); (2)int execle(const ch ...
随机推荐
- 转:如何制作一个定制的 PHP 基础 Docker 镜像(一)
原文来自于:http://open.daocloud.io/ru-he-zhi-zuo-yi-ge-ding-zhi-de-php-ji-chu-docker-jing-xiang/ 目标:准备一个定 ...
- Introduction to Gaussian Processes
Introduction to Gaussian Processes Gaussian processes (GP) are a cornerstone of modern machine learn ...
- RocketMQ在windows上安装和开发使用
1.概述 RocketMQ是alibaba公司开源的一个纯java的开源消息中间件. 2.开发测试环境搭建 到github上面rocketMQ,我选择的是alibaba-rocketmq-3.2.6. ...
- String.format 细节
String.format(Locale.US, format, args); format 参数 如果有% 那么%后面必须跟一个合法的字符,否则崩溃, 因为在String.format中 %为特殊字 ...
- POJ_2184_Cow_Exhibition_(动态规划,背包)
描述 http://poj.org/problem?id=2184 n只奶牛,每只都有智商s_i和情商f_i,取出若干只,保证智商之和与情商之和都不为负的情况下,让两者之和最大. Cow Exhibi ...
- android Spinner的使用
首先是MainActivity package com.example.spinnertest; import java.util.ArrayList; import java.util.List; ...
- ELK之topbeat部署
topbeat定期收集系统信息如每个进程信息.负载.内存.磁盘等等,然后将数据发送到elasticsearch进行索引,最后通过kibana进行展示. 下面是具体的安装及配置步骤: 1.安装topbe ...
- 【转】Xcode7.1环境下上架iOS App到AppStore 流程 (Part 一)
原文网址:http://www.cnblogs.com/ChinaKingKong/p/4957682.html 前言部分 之前App要上架遇到些问题到网上搜上架教程发现都是一些老的版本的教程 ,目前 ...
- (转载)Linux上iptables防火墙的基本应用教程
(转载)http://www.vpser.net/security/linux-iptables.html iptables是Linux上常用的防火墙软件,下面vps侦探给大家说一下iptables的 ...
- Device Tree常用方法解析
Device Tree常用方法解析 Device Tree在Linux内核驱动中的使用源于2011年3月17日Linus Torvalds在ARM Linux邮件列表中的一封邮件,他宣称“this w ...