设为首页 收藏本站
查看: 658|回复: 0

[经验分享] Linux 环境下 fork 函数和 exec 函数族的使用

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-10-27 08:37:31 | 显示全部楼层 |阅读模式
前言
  接触 Linux 已经有几个月了,以前在网上看各路大神均表示 Windows 是最烂的开发平台,我总是不以为然,但是经过这段时间琢磨,确实觉得 Linux 开发给我带来不少的便利。下面总结一下学习 Linux 多进程遇到的两个函数: fork( ) 和 exec( ) 函数族。

fork( )
  根据百度百科可以知道 fork 函数将运行着的程序分成2个(几乎)完全一样的进程,每个进程都启动一个从代码的同一位置开始执行的线程。所以如果成功对 fork 函数一次则返回两个值,子进程返回0,父进程返回子进程标记;否则,出错返回-1。
  例如:我们通过 while 条件来 fork 四个子进程,这四个进程完全由第一个进程创建。即这四个新的进程他们是兄弟关系,只是出生的时间不一样。
  

#include   
#include
  
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
  

DSC0000.jpg
  如果把这张图看成是以父进程为根节点的二叉树的话,那么所有叶子节点就是最终的进程个数,父进程不断调用 fork 函数,最终创建了四个新的进程。

exec( )函数族
  有 fork 函数我们知道fork出来的进程几乎是完全一样的,这感觉并没有什么用,所以我们想着使用这个新的进程去干点大事,例如运行一个别的程序 A ,一旦系统调用 exec() 函数族的函数,那么当前进程(也就是和父进程一样的进程)就死掉了,不再执行 fork() 后面的代码,即这个创建出来的进程就被进程 A 给替换了,系统重新分配资源,只留下进程号pid。
  先看一个例子,然后我们再说 exec() 函数族里面各个函数的区别:
  

#include   
#include
  
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
  

DSC0001.jpg
  恩,很明显 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”所指出的路径中进行查找。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-131177-1-1.html 上篇帖子: linux系统下搭建自己的web服务器 下篇帖子: linux中断源码分析
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表