27-fork 函数与分身术

初步体验进程的概念后,你也知道了你的 a.out 进程实际上是由终端 bash 进程创造出来的。那 bash 进程的父进程又是谁呢?如果你不断追溯下去,你就会发现,最终于那个进程就是 pid 为1 的 init 进程,而 init 进程,又是由一个 pid 为 0 的进程通过系统调用 fork 生成的,它也是第一个由 fork 函数创造出来的进程(linux 0.11 内核)。

fork 是本篇的重点,它是用户创建进程的唯一方法(万事都有特例,现阶段可忽略)。

1. fork 函数

fork 中文含义为“叉子”,这把叉子形状有点像中文的汉字“丫”,一个树干,两个分支。

如果你的 a.out 程序中有一个地方调用了 fork 函数,这时候你的 a.out 进程就会分出两条叉路,在这个分叉点,这两个进程几乎是“一毛一样”的。

1.1 学习分身咒语——fork

fork 函数恐怕是你到目前为止学习到的最简洁的函数了,它甚至连参数都没有:

pid_t fork(void);

这个函数神奇的地方在于,“一次调用两次返回”。这可能让你懵逼,那就举个例子让你明白。

有一天你学会了影分身术,念了一句咒语“急急如律令,分!”,一瞬间冒出了一个和你一模一样的人站在你身边。那个复制出来的你刚一出来就大喊“大家好,我是鸣人分身!”,同时你也大喊到“大家好,我是鸣人本体!”。

fork 函数就像那句咒语,而分身完成后,你和你的分身说的话,就相当于 fork 函数的返回值。

1.2 fork 函数的返回值

fork 函数返回值是 pid_t 类型,它就是通过 typedef 定义的一个 32 位的有符号整型数(32位 linux 系统)。不同的返回值,描述了进程的身份,到底是分身,还是本体?

  • >0 : 本体(调用 fork 的那个进程),这个值,是分身(子进程)的 id 号。
  • =0 :分身(子进程)
  • =1 :失败

2. 练习你的分身术

为了加深对 fork 的理解,具体看下面的例子。

2.1 实验代码

  • 代码
// myfork.c
#include <unistd.h>
#include <stdio.h>
#include <string.h>

int main() {
  char buf[] = "Hello, I'm father\n";
  write(STDOUT_FILENO, buf, strlen(buf));
  printf("before fork\n");

  pid_t pid = fork();


  if (!pid) {
    printf("I'm child %d; my father is %d\n", getpid(), getppid());
    sleep(2);
  }
  else if(pid > 0) {
    printf("I'm father %d; my child is %d\n", getpid(), pid); 
    sleep(2);
  }
  else {
    perror("fork");
    return 1;
  }
  return 0;
}
  • 编译
$ gcc myfork.c -o myfork
  • 运行
$ ./myfork
  • 结果
Hello, I'm father
before fork
I'm father 4382; my child is 4383
I'm child 4383; my father is 4382

2.2 结果分析

myfork 程序在调用 fork 前,先通过 write 和 printf 函数打印了两句不同的字符串。接下来调用 fork,fork 返回的的值保存在 pid 这个变量里。

你始终要记住,fork 是影分身口语,是本体念出来的;而返回值,是本体和分身都要念的。如何判断谁是本体谁是分身,就看本体和分身念的是什么。

在上面的代码里,返回值如果是 0 ,说明它是分身,是子进程,它不需要喊出自己的名字(对应于 pid),因为子进程可以通过 getpid 函数来知道自己的名字。

如果返回值大于 0,说明它是本体,因为本体需要知道自己分身的名字。

如果返回值等于 -1,很不幸,这次分身术失败。

3. 总结

  • 理解“分身术”
  • 理解 fork 函数及其返回值含义

其实,上面这段代码很不简单,坑也很多。如果你的程序还没删除,赶紧运行一下下面这个命令:

$ ./myfork > tmp

它把结果重定向到了 tmp 文件中,打开你的 tmp 文件看看吧!

不用惊慌,世界没有崩塌,请听下回分解。

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值