1 基本概述

1.1 孤儿进程和僵尸进程

父进程创建子进程后,较为理想状态是子进程结束,父进程回收子进程并释放子进程占有的资源;而实际上,父子进程是异步过程,两者谁先结束是无顺的,一般可以通过父进程调用wait()或waitpid()语句来等待子进程结束再退出。

孤儿进程:父进程结束后还有基于该父进程创建的子进程(一个或多个)尚没有结束,此时的子进程称之为孤儿进程;孤儿进程将被init进程(进程树中除了init都有父进程)接受,也就意味着init进程负责孤儿进程完成状态收集工作。一般而言,init进程的pid为1,有资料显示init有三种形式,其pid并不为1。

僵尸进程:在Linux进程状态及转换关系中有一种进程状态是僵尸状态(zombie),此时该进程称之为僵尸进程;当使用fork创建子进程后,子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程中的进程描述仍然保存在系统中,这种进程称之为僵尸进程,有时也称为僵死进程。

1.2 孤儿进程和僵尸进程危害

孤儿进程:孤儿进程不会占用系统资源,系统会将父进程回收处理孤儿进程,所以孤儿进程不占用系统资源;有时还会利用孤儿进程的这一原理进程程序逻辑设计。

僵尸进程:子进程先于父进程退出,父进程没有处理子进程的退出状态,此时子进程就会成为僵尸进程;进程已经结束,但是会占有一定的计算机资源。所以,我们应该尽量避免僵尸进程的产生。

Lunix提供了父进程获取子进程状态信息的机制;在每一个进程退出的时候,内核会释放该进程所有的资源,包括打开的文件、占用的内存等;但是仍然为其保留一定的信息(这些信息涵盖有进程号the process ID、退出状态the termination status of the process、运行时间the amount of CPU time taken by the process等),直到父进程调用wait() / waitpid()时才释放。

一个进程在调用exit命令结束自己的生命时,其实它并没有真正被销毁,而是留下一个称之为僵尸进程(Zombie)的数据结构(系统调用exit,它的作用是使进程退出,但也仅仅限于讲一个正常进程变成了一个僵尸进程,并不能将其完全销毁)。在Linux进程的状态中,僵尸进程是非常特殊的一种,它已经放弃了几乎所有内存空间,没有任何可执行代码,也不能被调度,仅仅在进程列表中保留一个位置,记载该进程的退出状态等信息供其他进程收集,除此之外,僵尸进程不再占有任何内存空间。它需要它的父进程来为它收尸,如果他的父进程没有安装SIGCHLD信号处理函数调用wait或waitpid等待子进程结束,又没有显式忽略该信号,那么它就一直保持僵尸状态,如果这时父进程结束了,那么init进程自动会接手这个子进程,为它收尸,它还是能被清除的。但是如果父进程是一个循环而不结束,那么子进程就会一直保持僵尸状态,如果如此进行下去,系统中就会遗留大量僵尸进程。

如何避免僵尸进程的产生?

1. 合理安排进程任务,尽量让父进程先结束

2. 父进程使用os.wait() os.waitpid() 来处理僵尸进程

3. 创建二级子进程,让一级子进程退出,从而形成两个完全独立的进程

4. 使用信号处理的方式

2 阻塞函数os.wait 与 os.waitpid 的基本语法

阻塞函数:当程序运行到该函数则进程处于阻塞状态不再继续运行 。一般在达到某些条件后结束阻塞

有大量IO操作或者可以给子进程操作,尽量让父进程先结束

阻塞函数不是不运行,而是等待某种事件的发生,如sleep就是阻塞等待函数

内核判断子进程是否结束,当子进程结束时,会通知应用层进行反馈

详情参考Python::OS 模块 -- 进程管理,里面详细阐述了os模块的属性

2.1 os.wait()

功能 : 阻塞等待子进程的退出,只要该父进程的任意子进程退出则终止阻塞。

参数:无

返回值:包含两个元素的元组,第一个 元素为退出的子进程的PID,第二个元素为子进程的退出码。

等待任何一个子进程结束,返回一个tuple,包括子进程的进程ID退出状态信息:一个16位的数字,低8位是杀死该子进程的信号编号,而高8位是退出状态(如果信号编号是0),其中低8位的最高位如果被置位,则表示产生了一个core文件。

  1. import os
  2. import sys
  3. from time import sleep
  4.  
  5. pid = os.fork()
  6.  
  7. if pid<0:
  8. print("create process failed")
  9. elif pid==0:
  10. print("this is chaild process:",os.getpid())
  11. sleep(2)
  12. sys.exit(2)
  13. else:
  14. p,status = os.wait()
  15. print("this is parena process")
  16. print("p=",p,"status=",status)
  17. print(os.WEXITSTATUS(status))

运行

  1. this is chaild process: 4088
  2. this is parena process
  3. p= 4088 status= 512
  4. 2

这里status=512 而sys.exit(2)中的值是2,其实他们是256倍数关系,这是计算机本身的一种算法;可以使用os.WEXITSTATUS(status)函数来将其计算成为想要的数值,也可以使用256倍数关系进行直接运算;但是不同系统存在有不同的算法规则,所以尽量采用函数调用来计算数值

2.2 os.waitpid(pid, options)

功能: 阻塞等待子进程的退出

参数: pid -1 表示任意子进程退出都可以处理

>0 表示指定pid的子进程退出才能处理

options : 0 表示一直阻塞等待

WNOHANG: 非阻塞等待

返回值 : 同wait

os.wait() ====> os.waitpid(-1,0)

等待进程id为pid的进程结束,返回一个tuple,包括进程的进程ID和退出信息(和os.wait()一样),参数options会影响该函数的行为。在默认情况下,options的值为0。

如果pid是一个正数,waitpid()请求获取一个pid指定的进程的退出信息;

如果pid为0,则等待并获取当前进程组中的任何子进程的值;

如果pid为-1,则等待当前进程的任何子进程;

如果pid小于-1,则获取进程组id为pid的绝对值的任何一个进程;

当系统调用返回-1时,抛出一个OSError异常。

  1. import os
  2. import sys
  3. from time import sleep
  4.  
  5. pid = os.fork()
  6.  
  7. if pid<0:
  8. print("create process failed")
  9. elif pid==0:
  10. print("this is chaild process:",os.getpid())
  11. sleep(2)
  12. sys.exit(2)
  13. else:
  14. p,status = os.waitpid(-1,0)#与刚才等价
  15. print("this is parena process")
  16. print("p=",p,"status=",status)
  17. print(os.WEXITSTATUS(status))

运行

  1. this is chaild process: 4296
  2. this is parena process
  3. p= 4296 status= 512
  4. 2

创建子子进程

  1. import os
  2.  
  3. pid = os.fork()
  4.  
  5. if pid<0:
  6. print("create process failed")
  7. elif pid==0:
  8. p = os.fork()
  9. if p<0:
  10. pass
  11. elif p==0:
  12. print("child--->child")
  13. else:
  14. os._exit(0)
  15. else:
  16. os.wait()
  17. print("this is parena process")

运行

  1. this is parena process
  2. child--->child

用的相关资源。

python学习笔记—— 多进程中的 孤儿进程和僵尸进程的更多相关文章

  1. python学习笔记——多进程中共享内存Value & Array

    1 共享内存 基本特点: (1)共享内存是一种最为高效的进程间通信方式,进程可以直接读写内存,而不需要任何数据的拷贝. (2)为了在多个进程间交换信息,内核专门留出了一块内存区,可以由需要访问的进程将 ...

  2. python学习笔记——多进程中的锁Lock

    1 进程锁 python编程中,引入了对象互斥锁的概念,来保证共享数据操作的完整性. 每个对象都对应于一个可称为“互斥锁”的标记,这个标记用来保证在任一时刻,只能有一线程访问对象. 在python中我 ...

  3. Python 学习笔记 多进程 multiprocessing--转载

    本文链接地址 http://quqiuzhu.com/2016/python-multiprocessing/ Python 解释器有一个全局解释器锁(PIL),导致每个 Python 进程中最多同时 ...

  4. python 学习笔记 多进程

    要让python程序实现多进程,我们先了解操作系统的相关知识 Unix/Linux操作系统提供了一个fork()系统调用,他非常特殊,普通的函数调用,调用一次,返回一次,但是fork调用一次, 返回两 ...

  5. python学习笔记-多进程

    multiprocessing from multiprocessing import Process import time def f(name): time.sleep(2) print('he ...

  6. python学习笔记——多进程一 基础概念

    1 进程 进程:程序的一次(从开始到结束)执行过程,属于一个动态过程.是系统进行资源分配和调度的基本单位. 程序:指的是一个文件,磁盘中可执行的代码.属于一个静态文件 注:进程运行时需要把程序加载如内 ...

  7. python学习笔记——多进程二 进程的退出

    1 进程的退出函数的基础语法 1.1 进程的退出函数 进程的退出含有有os._exit([status])和sys.exit([status])两种,从数据包来看,该退出模块仅在linux或者unix ...

  8. Python学习笔记——进阶篇【第八周】———进程、线程、协程篇(Socket编程进阶&多线程、多进程)

    本节内容: 异常处理 Socket语法及相关 SocketServer实现多并发 进程.线程介绍 threading实例 线程锁.GIL.Event.信号量 生产者消费者模型 红绿灯.吃包子实例 mu ...

  9. Python学习笔记6-Python中re(正则表达式)模块学习

    今天学习了Python中有关正则表达式的知识.关于正则表达式的语法,不作过多解释,网上有许多学习的资料.这里主要介绍Python中常用的正则表达式处理函数. re.match re.match 尝试从 ...

随机推荐

  1. LA 4728 Square ,旋转卡壳法求多边形的直径

    给出一些正方形.让你求这些正方形顶点之间的最大距离的平方. //返回点集直径的平方 int diameter2(vector<Point> & points) { vector&l ...

  2. 如何:使用TreeView控件实现树结构显示及快速查询

    本文主要讲述如何通过使用TreeView控件来实现树结构的显示,以及树节点的快速查找功能.并针对通用树结构的数据结构存储进行一定的分析和设计.通过文本能够了解如何存储层次结构的数据库设计,如何快速使用 ...

  3. easyui combotree模糊查询

    技术交流QQ群:15129679 让EasyUI的combobox和combotree同时支持自定义模糊查询,在不更改其他代码的情况下,添加以下代码就行了: /** * combobox和combot ...

  4. URL参数转换对象

    var parseQueryString = function (url) { var reg_url = /^[^\?]+\?([\w\W]+)$/, reg_para = /([^&=]+ ...

  5. 【python】理想论坛爬虫长贴版1.00

    理想论坛有些长贴,针对这些长贴做统计可以知道某ID什么时段更活跃. 爬虫代码为: #---------------------------------------------------------- ...

  6. Linux:编译动态库时遇到的错误relocation R_X86_64_32 against `a local symbol'

    编译动态库时遇到如下错误: ... ... relocation R_X86_64_32 against `a local symbol' can not be used when making a ...

  7. C#.NET常见问题(FAQ)-delegate委托链如何使用

    委托链本质就是你把一堆要执行的东西放到一个list里面,当要触发一组事情的时候,就不需要一个一个写一遍了(比如厂里食堂开饭了,这个方法一执行,要让厨师A时间在食堂等候打饭,B类员工在某个时间排队打饭, ...

  8. Hibernate(十)HQL查询二

    一.数据库的emp名和dept表 建立持久化类和配置文件,可以用MyEclipse直接生成 持久化类 package entity; import java.util.Date; public cla ...

  9. vue diff算法 patch

    1.diff比较算法 图示: diff比较只会在同层级进行, 不会跨层级比较. 所以diff是:广度优先算法. 时间复杂度:O(n) 代码示例: <!-- 之前 --> <div&g ...

  10. OA项目实战学习(7)——初始化数据&amp;权限配置显示

    详细有哪些功能: 初始化数据 权限数据. 超级管理员. Installer.java package cn.xbmu.oa.install; import javax.annotation.Resou ...