fork函数的定义

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

fork函数在父进程中返回子进程的pid,在子进程中返回0。注意在子进程中返回的0,并不是子进程的pid,子进程的pid在父进程的返回值中保存。而子进程的返回值是为了标识它是子进程,用来区分父子进程的。那么为什么这样设计父子进程的返回值呢?我的理解是这样的:第一,对于父进程来说,它可能同时有多个子进程,并且没有一个函数可以获得所有子进程的pid,所以它需要知道每个子进程的pid,这样便于管理各个子进程;第二,对于子进程来说,它父进程只能有一个,所以它可以不必实现和父进程类似的机制,获取父进程的pid,它可以通过getpid函数获取父进程的pid。而在内核中,进程pid为0,总是在内核交换进程时使用,所以进程的真实pid不可能为0。

资源相关问题

读时共享,写时复制

fork函数并不是在被调用时,为子进程copy一份父进程的副本,而是将父进程数据段、堆区和栈区的权限改变为只读。当父子进程中任何一个进程要修改该区域的值时,内核只会为修改区域的那块内存制作一个副本,通常是虚拟内存中的一页。这样的机制无需copy所有的父进程资源(这些资源在子进程中不一定有用),提高了程序的效率。但要注意,父子进程共享代码段。

复制的资源

  • 能够复制fork函数会复制数据段、堆区和栈区的资源
  • 能够复制参数表和环境表
  • 能够复制各个ID,但不包括PID
  • 不能够继承文件锁
1)数据段、堆区、栈区、参数表和环境表和上文说的一样,遵循读时共享,写时复制的机制;
2)环境表中只能改变其本身进程和其子进程的环境变量,无法改变其父进程的环境变量;
3)像是实际用户ID、实际组ID、有效用户ID、有效组ID、进程组ID和附属ID,这些都是进程的属性,所以存在于PCB中,每个进程都有自己的PCB节点,其中部分数据是继承父进程的。当然pid不会。
4)对于文件锁,子进程是不会被继承的。子进程虽然复制了文件描述符表,但都指向同一个文件表,当然了,文件表也就指向了同一个i节点。在i节点中保存着和文件锁相关的链表头节点(struct lockf)的地址。i节点资源不属于进程资源,而是文件资源,所以不会继承文件锁。

调用使用

常见使用方法

  • if...else结构:最常见的使用方法,很简单。
  • 和管道结合使用:主要用来父子进程间通信,使用时要注意,子进程会复制父进程的管道文件描述符,因此,都可以对对管道进行读写操作。需要注意的是,在使用管道这个临界资源时,不要忘记在软件逻辑上避免进程饥饿现象的产生。
  • 子进程的管理:别忘了了父进程能返回子进程的pid。当有多个子进程时,如果会用到各个子进程的pid的话,不要只是定义一个 pid_t pid

    的变量。这样的话,只能管理一个子进程哟!

避免僵尸进程的方法

  • 使用wait和waitpid函数:阻塞等待子进程结束,回收进程表资源
  • 安插信号:利用signal函数安插SIGCHLD信号。因为在子进程结束后,父进程会收到该信号。再自己写个回调函数,在函数中调用wait或waitpid函数,回收进程表资源;如果父进程对子进程结束不感兴趣,则可以利用“signal(SIGCHLD,SIG_IGN)”,将回收子进程资源的工作交给内核来做;但要注意,SIGCHLD信号是传统的不可靠信号,信号处理函数执行期间会暂时阻塞,因此,在这期前,如果又有了SIGCHLD信号,则会被抛弃,即无法处理多个SIGCHLD信号。所以信号处理函数的正确写法是:
void handler(int signs)
{
int tmp_errno=errno;
while(waitpid(-1,&status,WNOHANG)>0)
{
//处理返回信息
}
errno=tmp_errno;
}

但仍要注意的是,当waitpid返回值为-1时,会改变全局变量errno的值,如果这是在主程序中检测errno的值时,就很有可能发生冲突。因此,在进入信号处理函数之前要保存errno 的值,最后再回复errno的值。

  • 利用孤儿进程的机制:在创建的子进程中在调用fork函数,创建一个孙子进程,然后子进程终止,那么孙子进程就会被init进程收养。再当孙子进程结束时,回收进程资源的工作就交由了init进程去做。当然,有人会问,那么子进程结束后它的进程资源谁去回收?我说,那当然是父进程回收。这个时候能用父进程去回收子进程资源,是因为这是父子进程已经不在时异步的关系了。换句直白点的话说就是,父进程知道子进程在不久的将来一定会结束。回头想想,安插信号的方法的本质,不就是通过信号捕捉,确定了子进程会在不久的将来会结束吗?即在调用wait和外套pid时,不会阻塞等待很长时间就能返回,不会影响父进程自身的工作。
注意:安插信号和利用孤儿进程的机制来避免僵尸进程的方法,不仅仅能避免僵尸进程,还能不影响父进程本身的工作任务,这一点是非常有用的。

进程管理之fork函数的更多相关文章

  1. UNIX环境编程学习笔记(19)——进程管理之fork 函数的深入学习

    lienhua342014-10-07 在“进程控制三部曲”中,我们学习到了 fork 是三部曲的第一部,用于创建一个新进程.但是关于 fork 的更深入的一些的东西我们还没有涉及到,例如,fork ...

  2. Linux -- 进程管理之 fork() 函数

    一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己. Test1 f ...

  3. 进程控制之fork函数

    一个现有进程可以调用fork函数创建一个新进程. #include <unistd.h> pid_t fork( void ); 返回值:子进程中返回0,父进程中返回子进程ID,出错返回- ...

  4. 【Linux编程】进程标识符与fork函数

    ID为0的进程一般是调度进程.常被称为交换进程(swapper),是内核中的系统进程. ID为1的进程叫做init进程,是一个普通用户进程,不属于内核,由内核调用. 一个现有进程能够调用fork函数创 ...

  5. [Chapter 3 Process]Practice 3.1 相关知识:进程创建、fork函数

    3.1 Using the program shown in the Figure3.30, explain what the output will be at LINE A 答案:LINE A 处 ...

  6. Linux0.11 创建进程的过程分析--fork函数的使用

    /* * linux/kernel/fork.c * * (C) 1991 Linus Torvalds */ /* 注意:signal.c和fork.c文件的编译选项内不能有vc变量优化选项/Og, ...

  7. UNIX环境编程学习笔记(22)——进程管理之system 函数执行命令行字符串

    lienhua342014-10-15 ISO C 定义了 system 函数,用于在程序中执行一个命令字符串.其声明如下, #include <stdlib.h> int system( ...

  8. UNIX环境高级编程——进程管理和通信(总结)

    进程管理与通信 进程的管理 进程和程序的区别: 进程: 程序的一次执行过程   动态过程,进程的状态属性会发生变化 程序:存放在磁盘上的指令.数据的有序集合  是个文件,可直观看到 程序program ...

  9. 深入浅出--UNIX多进程编程之fork()函数

    0前言 上周都在看都在学习unix环境高级编程的第八章--进程控制.也就是这一章中.让我理解了unix中一些进程的原理.以下我就主要依照进程中最重要的三个函数来进行解说.让大家通过阅读这一篇文章彻底明 ...

随机推荐

  1. 一个简单的时间轴demo

    一个时间轴的组成 使用一个块级元素包裹内容,并未块级元素设置边框 定义圆形或者菱形等元素标签,子元素设置偏移或者定位元素将图标定位到边框上 使其中的内容不溢出,自动换行,内容自动撑高 英文自动换行:w ...

  2. webpack热更新问题和antd design字体图标库扩展

    标题也不知道怎么写好,真是尴尬.不过话说回来,距离上一次写文快两个月了,最近有点忙,一直在开发新项目, 今天刚刚闲下来,项目准备提测.借这个功夫写点东西,把新项目上学到的一些好的干活分享一下,以便之后 ...

  3. vue数据绑定原理

    一.定义 vue的数据双向绑定是基于Object.defineProperty方法,通过定义data属性的get和set函数来监听数据对象的变化,一旦变化,vue利用发布订阅模式,通知订阅者执行回调函 ...

  4. linux下 git 安装

    1.使用yum安装 yum -y install git yum remove git 2.源代码安装 a.下载git源码  网址为 https://github.com/git/git/releas ...

  5. eclipse连接hadoop问题

    1,首先可以测试:hafs dfsadmin -safemode leave2,如果出现下面的问题Error:Permission denied: user= ,access=READ_EXECUTE ...

  6. android studio生成junitLibs

    apply plugin: 'com.android.application'android { compileSdkVersion 24 buildToolsVersion "25.0.0 ...

  7. markdown 常用格式API

    摘要 记录常用格式 参考:https://www.zybuluo.com/mdeditor 1. 标题 写法: 文字前加 #, 几个# 表示几级标题 标题下方增加 = 或 - 效果 标题1 标题2 标 ...

  8. HTML基础知识(未完待续)

    一.HTML编辑工具:Sublime Text 二.HTML实体字符:1.( 空格):&nbsp: 2.(<) &lt: 3.(>)&gt: 4.(&)&a ...

  9. 简单聊聊不可或缺的Nginx反向代理服务器--实现负载均衡【上篇】

    今天又是新的一周,我养足了精神去对待新一周的工作,但是今天到公司发现还是有一点空闲时间的,所以就想与之前接触过的Nginx再交往得更深一点儿. 什么是Nginx: Nginx是一款高性能的http服务 ...

  10. Json 工具介绍 fastjson gson jackson

    1. fastjson fastjson是一个Java语言编写的高性能功能完善的JSON库.它采用一种“假定有序快速匹配”的算法,把JSON Parse的性能提升到极致, 是目前Java语言中最快的J ...