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. Maven学习专题--Maven入门及安装

    因为项目需要,新项目需要使用Maven开发,但是组内大部分没有接触过maven.我就毅然承担搭建maven环境的任务了.因为一切重头开始,就想把自己的整个搭建环境.项目创建.框架整合和模块管理整个过程 ...

  2. 将 MacOS 默认的 PHP 版本升级到 7.*

    上接:在macOS Sierra 10.12搭建PHP开发环境 设置 brew brew tap homebrew/dupes brew tap homebrew/versions brew tap ...

  3. 【无旋式treap】例题

    [bzoj3223]文艺平衡树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[ ...

  4. WEB安全:文件上传漏洞

    文件上传漏洞过程 用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力. 一般的情况有: 上传文件WEB脚本语言,服务器的WEB容器解释并执行了用户上传的脚本,导致代码执行: ...

  5. 对于mariadb安装后可以默认使用无密码登录的问题解决方案

    mariadb安装后默认可以无密码登录 所以首先我们要设置root用户的密码 mysqladmin -u root -p password 密码 [遇到enter直接enter就行,注意,如果是重新设 ...

  6. select可选择、同时可自行输入

    HTML部分: <li class="bl-form-group"> <label>诊断医生</label> <div class=&qu ...

  7. Objective-C 自定义UISlider滑杆 分段样式

    效果 自定义一个功能简单的分段的滑杆 可显示分段名 为了显示效果,我们将滑块和节点都设置为不规则 这里只实现了分段的slider,未分段的没有实现,有兴趣的可以定义另一种类型做个判断修改下 需求分析 ...

  8. 【Owin 学习系列】2. Owin Startup 类解析

    Owin Startup 类解析 每个 Owin 程序都有 startup 类,在这个 startup 类里面你可以指定应用程序管道模型中的组件.你可以通过不同的方式来连接你的 startup 类和运 ...

  9. 权限管理学习 一、ASP.NET Forms身份认证

    说明:本文示例使用的VS2017和MVC5. 系统无论大小.牛逼或屌丝,一般都离不开注册.登录.那么接下来我们就来分析下用户身份认证. 简单实现登录.注销 以前在学习.net的时候不知道什么Forms ...

  10. CentOS服务器运维监控Nagios(一)

    CentOS下搭建Nagios 王尚 2014.11.09 操作系统:CentOS-6.5-i386-bin-DVD1.iso 安装在VM中进行测试的. 本章需要的软件链接: php-5.3.2.ta ...