进程管理之fork函数
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函数的更多相关文章
- UNIX环境编程学习笔记(19)——进程管理之fork 函数的深入学习
lienhua342014-10-07 在“进程控制三部曲”中,我们学习到了 fork 是三部曲的第一部,用于创建一个新进程.但是关于 fork 的更深入的一些的东西我们还没有涉及到,例如,fork ...
- Linux -- 进程管理之 fork() 函数
一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间.然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同.相当于克隆了一个自己. Test1 f ...
- 进程控制之fork函数
一个现有进程可以调用fork函数创建一个新进程. #include <unistd.h> pid_t fork( void ); 返回值:子进程中返回0,父进程中返回子进程ID,出错返回- ...
- 【Linux编程】进程标识符与fork函数
ID为0的进程一般是调度进程.常被称为交换进程(swapper),是内核中的系统进程. ID为1的进程叫做init进程,是一个普通用户进程,不属于内核,由内核调用. 一个现有进程能够调用fork函数创 ...
- [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 处 ...
- Linux0.11 创建进程的过程分析--fork函数的使用
/* * linux/kernel/fork.c * * (C) 1991 Linus Torvalds */ /* 注意:signal.c和fork.c文件的编译选项内不能有vc变量优化选项/Og, ...
- UNIX环境编程学习笔记(22)——进程管理之system 函数执行命令行字符串
lienhua342014-10-15 ISO C 定义了 system 函数,用于在程序中执行一个命令字符串.其声明如下, #include <stdlib.h> int system( ...
- UNIX环境高级编程——进程管理和通信(总结)
进程管理与通信 进程的管理 进程和程序的区别: 进程: 程序的一次执行过程 动态过程,进程的状态属性会发生变化 程序:存放在磁盘上的指令.数据的有序集合 是个文件,可直观看到 程序program ...
- 深入浅出--UNIX多进程编程之fork()函数
0前言 上周都在看都在学习unix环境高级编程的第八章--进程控制.也就是这一章中.让我理解了unix中一些进程的原理.以下我就主要依照进程中最重要的三个函数来进行解说.让大家通过阅读这一篇文章彻底明 ...
随机推荐
- Maven学习专题--Maven入门及安装
因为项目需要,新项目需要使用Maven开发,但是组内大部分没有接触过maven.我就毅然承担搭建maven环境的任务了.因为一切重头开始,就想把自己的整个搭建环境.项目创建.框架整合和模块管理整个过程 ...
- 将 MacOS 默认的 PHP 版本升级到 7.*
上接:在macOS Sierra 10.12搭建PHP开发环境 设置 brew brew tap homebrew/dupes brew tap homebrew/versions brew tap ...
- 【无旋式treap】例题
[bzoj3223]文艺平衡树 Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:翻转一个区间,例如原有序序列是5 4 3 2 1,翻转区间是[ ...
- WEB安全:文件上传漏洞
文件上传漏洞过程 用户上传了一个可执行的脚本文件,并通过此脚本文件获得了执行服务器端命令的能力. 一般的情况有: 上传文件WEB脚本语言,服务器的WEB容器解释并执行了用户上传的脚本,导致代码执行: ...
- 对于mariadb安装后可以默认使用无密码登录的问题解决方案
mariadb安装后默认可以无密码登录 所以首先我们要设置root用户的密码 mysqladmin -u root -p password 密码 [遇到enter直接enter就行,注意,如果是重新设 ...
- select可选择、同时可自行输入
HTML部分: <li class="bl-form-group"> <label>诊断医生</label> <div class=&qu ...
- Objective-C 自定义UISlider滑杆 分段样式
效果 自定义一个功能简单的分段的滑杆 可显示分段名 为了显示效果,我们将滑块和节点都设置为不规则 这里只实现了分段的slider,未分段的没有实现,有兴趣的可以定义另一种类型做个判断修改下 需求分析 ...
- 【Owin 学习系列】2. Owin Startup 类解析
Owin Startup 类解析 每个 Owin 程序都有 startup 类,在这个 startup 类里面你可以指定应用程序管道模型中的组件.你可以通过不同的方式来连接你的 startup 类和运 ...
- 权限管理学习 一、ASP.NET Forms身份认证
说明:本文示例使用的VS2017和MVC5. 系统无论大小.牛逼或屌丝,一般都离不开注册.登录.那么接下来我们就来分析下用户身份认证. 简单实现登录.注销 以前在学习.net的时候不知道什么Forms ...
- CentOS服务器运维监控Nagios(一)
CentOS下搭建Nagios 王尚 2014.11.09 操作系统:CentOS-6.5-i386-bin-DVD1.iso 安装在VM中进行测试的. 本章需要的软件链接: php-5.3.2.ta ...