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文件。

import os
import sys
from time import sleep

pid = os.fork()

if pid<0:
    print("create process failed")
elif pid==0:
    print("this is chaild process:",os.getpid())
    sleep(2)
    sys.exit(2)
else:
    p,status = os.wait()
    print("this is parena process")
    print("p=",p,"status=",status)
    print(os.WEXITSTATUS(status))

运行

this is chaild process: 4088
this is parena process
p= 4088 status= 512
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异常。

import os
import sys
from time import sleep

pid = os.fork()

if pid<0:
    print("create process failed")
elif pid==0:
    print("this is chaild process:",os.getpid())
    sleep(2)
    sys.exit(2)
else:
    p,status = os.waitpid(-1,0)#与刚才等价
    print("this is parena process")
    print("p=",p,"status=",status)
    print(os.WEXITSTATUS(status))

运行

this is chaild process: 4296
this is parena process
p= 4296 status= 512
2

创建子子进程

import os

pid = os.fork()

if pid<0:
    print("create process failed")
elif pid==0:
    p = os.fork()
    if p<0:
        pass
    elif p==0:
        print("child--->child")
    else:
        os._exit(0)
else:
    os.wait()
    print("this is parena process")

运行

this is parena process
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. 给定任意字符串,计算一共能组合成多少个单词bing

    CSDN编程挑战里的题目 例如有一个字符串"iinbinbing",截取不同位置的字符‘b’.‘i’.‘n’.‘g’组合成单词"bing".若从1开始计数的话, ...

  2. perfect-rectangle

    https://leetcode.com/problems/perfect-rectangle/ // https://discuss.leetcode.com/topic/55944/o-n-log ...

  3. 第十二章 ThreadPoolExecutor使用 + 工作机理 + 生命周期

    1.最基础的线程池ThreadPoolExecutor 使用方式: /** * ThreadPoolExecutor测试类 * 注意: * 1.ThreadPoolExecutor是一个线程池 * 2 ...

  4. Metronic V1.5.2 Responsive Admin Dashboard Template build with Twitter Bootstrap 3.0

    Template Name: Metronic - Responsive Admin Dashboard Template build with Twitter Bootstrap 3.0 Versi ...

  5. 以太网帧、IP报文格式

    这几天完成一个对比以太网帧的程序(c语言),老师给了以太网帧头部和IP报文头部的结构体,跟实际抓取到的数据包的格式是相同的. 以太网帧头部的数据结构: typedef struct { unsigne ...

  6. [Unity-6] GameObject有时候渲染不出来

    问题描写叙述:在做游戏的过程中遇到了这样一个问题.一个怪物,假设让他出如今屏幕的中央是没问题的,可是让他出如今屏幕的边缘的位置发现他没有出现. 问题原因:经过检查发现,我给这个GameObject加入 ...

  7. java编程思想---对象

    一.对象 对于每种语言来说,都有自己操纵内存中元素的方法. 在java中,一切被视为对象.可是操纵对象的是一个"引用".举个样例,能够比作为遥控器对电视的操作,遥控器就是引用,而电 ...

  8. docker入门——构建镜像

    前面我们已经介绍了如何拉取已经构建好的带有定制内容的Docker镜像,那么如何构建自己的镜像呢? 构建Docker镜像有以下两种方法: 使用docker commit命令. 使用docker buil ...

  9. 封装scrollView 循环滚动,tableViewCell(连载) mvc

    封装 封装 封装 ... 封装的重要性太重要了 给大家在送点干货 从一个项目中抽取出来的.和大家一起分享 封装scrollView 循环滚动.tableViewCell(连载) 明天还会更新 tabl ...

  10. jQuery Mobile的学习时间bottonbutton的事件学习

    程序猿都非常懒.你懂的! 生命的绝唱来机仅仅争朝夕,如诗的年华更需惜时如金. 不要让今天的懈怠成为一生的痛. 每天都在进步. 近期在学习jquery mobile开发.使用的button,绑定事件,和 ...