Linux 环境下 fork 函数和 exec 函数族的使用
前言
接触 Linux 已经有几个月了,以前在网上看各路大神均表示 Windows 是最烂的开发平台,我总是不以为然,但是经过这段时间琢磨,确实觉得 Linux 开发给我带来不少的便利。下面总结一下学习 Linux 多进程遇到的两个函数: fork( ) 和 exec( ) 函数族。
fork( )
根据百度百科可以知道 fork 函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。所以如果成功对 fork 函数一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。
例如:我们通过 while 条件来 fork 四个子进程,这四个进程完全由第一个进程创建。即这四个新的进程他们是兄弟关系,只是出生的时间不一样。
#include <stdio.h>
#include <unistd.h>
int main()
{
int ppid = getpid();
printf("我是父进程,我的pid是 %d ... 我要创建四个新的进程!\n", ppid);
int count = 0;
while (count < 4) {
int fpid = fork();
count++;
if (fpid > 0) { //fork() 返回值大于0为父进程,返回值表示子进程的pid
printf("我是父进程, 我是 %d 的父亲.\n", fpid);
} else if (fpid == 0) { //fork() 返回值等于0为子进程
int pid = getpid();
printf("我是第 %d 个新进程, 我的pid是 %d, 我的父亲是 %d\n", count, pid, ppid);
return -1; //我们这里是用父进程创建子进程,而不想让子进程也创建子进程,所以return
} else {
printf("Error in fork!");
}
}
return 0;
}
上面的代码执行后的结果为:
pengzhendong@Randy ~/Code> gcc ./concurrent.c -o ./concurrent
pengzhendong@Randy ~/Code> ./concurrent
我是父进程,我的pid是 37515 ... 我要创建四个新的进程!
我是父进程, 我是 37516 的父亲.
我是父进程, 我是 37517 的父亲.
我是第 1 个新进程, 我的pid是 37516, 我的父亲是 37515
我是第 2 个新进程, 我的pid是 37517, 我的父亲是 37515
我是父进程, 我是 37518 的父亲.
我是父进程, 我是 37519 的父亲.
我是第 3 个新进程, 我的pid是 37518, 我的父亲是 37515
我是第 4 个新进程, 我的pid是 37519, 我的父亲是 37515

如果把这张图看成是以父进程为根节点的二叉树的话,那么所有叶子节点就是最终的进程个数,父进程不断调用 fork 函数,最终创建了四个新的进程。
exec( )函数族
有 fork 函数我们知道fork出来的进程几乎是完全一样的,这感觉并没有什么用,所以我们想着使用这个新的进程去干点大事,例如运行一个别的程序 A ,一旦系统调用 exec() 函数族的函数,那么当前进程(也就是和父进程一样的进程)就死掉了,不再执行 fork() 后面的代码,即这个创建出来的进程就被进程 A 给替换了,系统重新分配资源,只留下进程号pid。
先看一个例子,然后我们再说 exec() 函数族里面各个函数的区别:
#include <stdio.h>
#include <unistd.h>
int main(int argc, char *argv[])
{
int pid = fork();
if (pid > 0) {
printf("我是父进程.........\n");
} else if (pid == 0) {
if (argc < 3) {
printf("参数太少!\n");
return -1;
}
printf("我是新进程, 我要执行 %s....\n", argv[2]);
char * const *argvs = &argv[2];
execvp(argv[1], argvs);
printf("看看你能不能打印这句话!");
} else {
printf("Error in fork!");
}
return 0;
}
上面代码创建了一个子进程,然后子进程通过系统调用去执行了一个新的程序,就直接执行刚刚那个程序吧!
pengzhendong@Randy ~/Code> gcc ./exer2.c -o ./exer2
pengzhendong@Randy ~/Code> ./exer2 ./concurrent ./concurrent
我是父进程.........
我是新进程, 我要执行 ./concurrent....
我是父进程,我的pid是 37790 ... 我要创建四个新的进程!
我是父进程, 我是 37795 的父亲.
我是父进程, 我是 37796 的父亲.
我是第 1 个新进程, 我的pid是 37795, 我的父亲是 37790
我是第 2 个新进程, 我的pid是 37796, 我的父亲是 37790
我是父进程, 我是 37797 的父亲.
我是第 3 个新进程, 我的pid是 37797, 我的父亲是 37790
我是父进程, 我是 37798 的父亲.
我是第 4 个新进程, 我的pid是 37798, 我的父亲是 37790

恩,很明显 printf("看看你能不能打印这句话!"); 这段代码并不能执行,因为调用exec()函数族之后,和父进程一样的子进程就被杀死了~
现在我们来讨论一下 exec() 函数族里的函数有什么区别,在这之前想先提一下环境变量这个东西,要是想在命令行里面直接通过输入程序的名字来调用一个程序,那么我们就要把这个程序的绝对路径加到环境变量里面去,就是你直接用这个程序的时候不用输入再绝对路径,你只要输入程序的名字,系统就会自动去环境变量里面找他的绝对路径:
exec家族一共有六个函数,分别是:
(1)int execl(const char *path, const char *arg, ......);
(2)int execle(const char *path, const char *arg, ...... , char * const envp[]);
(3)int execv(const char *path, char *const argv[]);
(4)int execve(const char *filename, char *const argv[], char *const envp[]);
(5)int execvp(const char *file, char * const argv[]);
(6)int execlp(const char *file, const char *arg, ......);
L:参数传递为逐个列举方式: execl execle execlp
V:参数传递为构造指针数组方式: execv execve execvp
E:可传递新进程环境变量: execle execve
P:可执行文件查找方式为文件名: execlp execvp
前四个函数的查找方式都是完整的文件目录路径,而最后两个函数(以p结尾的函数)可以只给出文件名,系统就会自动从环境变量“$PATH”所指出的路径中进行查找。
Linux 环境下 fork 函数和 exec 函数族的使用的更多相关文章
- [转帖]Linux下fork函数及pthread函数的总结
Linux下fork函数及pthread函数的总结 https://blog.csdn.net/wangdd_199326/article/details/76180514 fork Linux多进程 ...
- 多线程编程之Linux环境下的多线程(一)
一.Linux环境下的线程 相对于其他操作系统,Linux系统内核只提供了轻量级进程的支持,并未实现线程模型.Linux是一种“多进程单线程”的操作系统,Linux本身只有进程的概念,而其所谓的“线程 ...
- 针对 Linux 环境下 gdb 动态调试获取的局部变量地址与直接运行程序时不一致问题的解决方案
基础的缓冲区溢出实践通常需要确定运行状态下程序中的某些局部变量的地址,如需要确定输入缓冲区的起始地址从而获得注入缓冲区中的机器指令的起始地址等.在 Linux 环境下,可通过 gdb 对程序进行动态调 ...
- PHP 命令行模式实战之cli+mysql 模拟队列批量发送邮件(在Linux环境下PHP 异步执行脚本发送事件通知消息实际案例)
源码地址:https://github.com/Tinywan/PHP_Experience 测试环境配置: 环境:Windows 7系统 .PHP7.0.Apache服务器 PHP框架:ThinkP ...
- linux环境下学习使用pro*c/c++工具
1.proc是oracle用来预编译嵌入SQL语句的c程序. 2.如何使用proc工具 在Linux环境下,首先确保gcc编译器正常使用,安装oracle数据库或者客户端,一般就会默认安装pro*c/ ...
- Linux环境下段错误的产生原因及调试方法小结(转)
最近在Linux环境下做C语言项目,由于是在一个原有项目基础之上进行二次开发,而且 项目工程庞大复杂,出现了不少问题,其中遇到最多.花费时间最长的问题就是著名的“段错误”(Segmentation F ...
- 【环境配置】Linux环境下下载、配置java环境、安装eclipse、建立eclipse快捷方式详解
一.首先是下载Java JDK 到目前为止的最新版本为(jdk1.8.0_60),有两种方式进行下载: 1.使用shell来进行下载,可使用如下命令直接进行下载: wget --no-check-ce ...
- Linux环境下段错误的产生原因及调试方法小结
转载自http://www.cnblogs.com/panfeng412/archive/2011/11/06/2237857.html 最近在Linux环境下做C语言项目,由于是在一个原有项目基础之 ...
- linux环境下安装sphinx中文支持分词搜索(coreseek+mmseg)
linux环境下安装sphinx中文支持分词搜索(coreseek+mmseg) 2013-11-10 16:51:14 分类: 系统运维 为什么要写这篇文章? 答:通过常规的三大步(./confi ...
随机推荐
- SPOJ 7258 Lexicographical Substring Search(后缀自动机)
[题目链接] http://www.spoj.com/problems/SUBLEX/ [题目大意] 给出一个字符串,求其字典序排名第k的子串 [题解] 求出sam上每个节点被经过的次数,然后采用权值 ...
- openStack error infos 调试
glance image-create --name "RuiCheck" --disk-format qcow2 --container-format bare --is-pub ...
- UVA 11549 Calculator Conundrum (Floyd判圈算法)
题意:有个老式计算器,每次只能记住一个数字的前n位.现在输入一个整数k,然后反复平方,一直做下去,能得到的最大数是多少.例如,n=1,k=6,那么一次显示:6,3,9,1... 思路:这个题一定会出现 ...
- InnoDB引擎Myslq数据库数据恢复
首先祝愿看到这片文章的你永远不要有机会用到它... 本文指针对用InnoDB引擎的Mysql数据库的数据恢复,如果是其它引擎的Mysql或其它数据库请自行google... 如果有一天你手挫不小心删掉 ...
- The Highest Mark(01背包)
The Highest Mark Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 131072/131072 K (Java/Other ...
- [置顶] 【cocos2d-x入门实战】微信飞机大战之二:别急,先处理好CCScene和CCLayer的关系
转载请表明地址:http://blog.csdn.net/jackystudio/article/details/11713197 在整个游戏开始之前,我们先看一下HelloWorld示例中CCSce ...
- 九度OnlineJudge之1012:畅通工程
题目描述: 某省调查城镇交通状况,得到现有城镇道路统计表,表中列出了每条道路直接连通的城镇.省政府“畅通工程”的目标是使全省任何两个城镇间都可以实现交通(但不一定有直接的道路相连,只要互相间接通过道路 ...
- 浅谈Struts2(四)
一.Struts2的拦截器(Intercept) 作用:把多个Action中的共有代码,提取至拦截器,从而减少Action中的冗余代码. 1.Action拦截器 a.编写interceptor类 pu ...
- Yii2.0中文开发向导——删除数据
直接 model 删除 $model = User::find($id); $model->delete(); 带有条件的删除 $connection ->createCommand() ...
- Firefox 备份
参考http://mozilla.com.cn/post/32327/ 火狐的地址栏中输入about:support点击“打开所在文件夹”按钮,会弹出一个资源管理器,并且定位到你当前的Profile文 ...