我是靠谱客的博主 内向音响,最近开发中收集的这篇文章主要介绍fork子进程,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

目录

    • 一、相关函数
    • 二、详解
      • 1、fork的使用
      • 2、孤儿进程
      • 3、僵尸进程

一、相关函数

fork函数:创建一个新的进程,当前进程是新进程的父进程
通过man 2 fork命令可以查看linux手册中第二节关于fork函数的介绍

 #include <unistd.h>
  pid_t fork(void);

fork函数会返回两次,一次在父进程、一次在子进程。它有3中可能的返回结果:

  • -1:创建失败,在父进程中返回-1
  • 0:创建成功,当前进程是子进程
  • 其他:创建成功,在父进程中返回子进程的pid(进程 ID)

需要注意:fork的操作比较重,fork出来的子进程会获得父进程的完整副本,当然了Linux不是在子进程一fork出来就将父进程的资源复制出一个副本给子进程的,Linux采用了写时复制,一开始两个进程是共享数据的,但是当子进程尝试修改数据,就会触发写时复制,为子进程创建一个该数据的副本。

linux系统还提供了一些函数,用来获取进程 ID,查看手册man 2 getpid结果如下:

 #include <unistd.h>
 //获取当前进程的pid
 pid_t getpid(void);
 //获取父进程的pid
 pid_t getppid(void);

二、详解

1、fork的使用

编写 forkdemo.c,代码如下:

#include <unistd.h>
#include <stdio.h>
int main(){
    printf("before forkn");
    pid_t pid=fork();
    if(pid == -1){
      printf("创建子进程失败");
    }else if(pid == 0){
      printf("我是子进程,我的pid是:%d,父进程的pid是:%dn",getpid(),getppid());
    }else{
      sleep(1);
      printf("我是父进程,我的pid是:%d,子进程的pid是:%dn",getpid(),pid);
    }
    printf("after forkn");
}

编译 gcc forkdemo.c -o forkdemo 后执行./forkdemo,结果如下:

before fork
我是子进程,我的pid是:28473,父进程的pid是:28472
after fork
我是父进程,我的pid是:28472,子进程的pid是:28473
after fork

从结果可以看出,fork函数会返回两次,在子进程中返回0,父进程中返回的是子进程的pid,这里让父进程sleep 1s是为了保证子进程先执行完。

  • 问题:子进程中为什么也是从fork出开始执行,为什么不从main函数开始执行?
    通过执行 fork系统调用,子进程获得父进程中数据空间,堆和栈等的副本,但它们并不共享存储空间,只共享代码段。由于把当前运行的位置都复制到子进程 ,那么子进程当然也是接着fork继续执行。

2、孤儿进程

现在如果我让子进程 sleep(1), 让父进程先执行完会如何呢?修改后代码如下:

#include <unistd.h>
#include <stdio.h>
int main(){
    printf("before forkn");
    pid_t pid=fork();
    if(pid == -1){
      printf("创建子进程失败");
    }else if(pid == 0){
      //子进程休眠1s
      sleep(1);
      printf("我是子进程,我的pid是:%d,父进程的pid是:%dn",getpid(),getppid());
    }else{
      printf("我是父进程,我的pid是:%d,子进程的pid是:%dn",getpid(),pid);
    }
    printf("after forkn");
}

编译执行后结果如下:

before fork
我是父进程,我的pid是:28513,子进程的pid是:28514
after fork
我是子进程,我的pid是:28514,父进程的pid是:1
after fork
  • 问题:父进程先结束了,然后子进程的父进程不再是创建它的那个进程了,这是为何?

要知道为什么有这个结果,首先要知道什么是孤儿进程?
孤儿进程:父进程先于子进程结束,则子进程会成为孤儿进程。
借助现实的例子:作为一个单亲父亲的孩子,如果他的父亲死亡了,那么这个孩子就会成为孤儿,会有专门的机构"孤儿院"来收养这个孩子。
Linux中托孤的行为和这个例子很相似,当父进程运行结束,但子进程还在运行,那么这个子进程就会变为孤儿进程,为避免孤儿进程退出时无法释放相关的资源(进程描述符)而变为僵尸进程,所以孤儿进程会被 init 进程(pid 为 1 )所 “收养”,由init进程来进行“善后”。

3、僵尸进程

当一个进程完成它的工作终止后,它的所有资源都会被回收,但是该进程的进程描述符依然被保留了,这是为了让父进程可以知道子进程的退出状态,因此进程结束后所占用资源的回收和进程描述符的释放是分开的。它的父进程可以调用wait()或waitpid()系统调用来取得子进程的终止状态,然后内核负责回收子进程残留的进程描述符等资源。需要注意这其实就是僵尸进程产生的原因,虽然子进程结束了,但是它的进程描述符依然被保留,没被释放。

#include <unistd.h>
#include <stdio.h>
#include <sys/wait.h>
int main(){
    printf("before forkn");
    pid_t pid=fork();
    if(pid == -1){
      printf("创建子进程失败");
    }else if(pid == 0){
      sleep(3);
      printf("我是子进程,我的pid是:%d,父进程的pid是:%dn",getpid(),getppid());
    }else{
      printf("我是父进程,我的pid是:%d,子进程的pid是:%dn",getpid(),pid);
      int status;
      //作用:阻塞等待子进程结束、获取子进程的退出状态status、回收子进程残留资源
      wait(&status);
     printf("我是父进程,子进程已经被回收,我也要结束了n");
    }
    printf("after forkn");
}

最后

以上就是内向音响为你收集整理的fork子进程的全部内容,希望文章能够帮你解决fork子进程所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(33)

评论列表共有 0 条评论

立即
投稿
返回
顶部