首页 > 系统相关 >僵尸进程和孤儿进程、守护进程

僵尸进程和孤儿进程、守护进程

时间:2024-05-27 18:34:23浏览次数:16  
标签:__ task name print pid 孤儿 进程 守护

【一】僵尸进程和孤儿进程

【1】引入

  • 我们知道在unix/linux中,正常情况下,子进程是通过父进程创建的,子进程在创建新的进程。
  • 子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程 到底什么时候结束。
  • 当一个 进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。

【2】僵尸进程(有害)

[1] 什么是僵尸进程

  • 僵尸进程是指完成了自己的任务,但父进程没有正确地释放它所占用的系统资源
  • 导致它仍然存在于进程列表中,但已经停止了运行
  • 这些僵尸进程会占据一定的系统内存,并在一定程度上影响系统的性能。

[2] 解决办法(UNIX系统)

  • 因此,UNⅨ提供了一种机制可以保证父进程可以在任意时刻获取子进程结束时的状态信息

    • 在每个进程退出的时候,内核释放该进程所有的资源,包括打开的文件,占用的内存等。
      • 但是仍然为其保留一定的信息(包括进程号the process ID,退出状态the termination status of the process,运行时间the amount of CPU time taken by the process等)
    • 直到父进程通过wait / waitpid来取时才释放.
      • 但这样就导致了问题,如果进程不调用wait / waitpid的话,那么保留的那段信息就不会释放,其进程号就会一直被占用,但是系统所能使用的进程号是有限的
      • 如果大量的产生僵死进程,将因为没有可用的进程号而导致系统不能产生新的进程. 此即为僵尸进程的危害,应当避免。
  • 任何一个子进程(init除外)在exit()之后,并非马上就消失掉,而是留下一个称为僵尸进程(Zombie)的数据结构,等待父进程处理。

    • 这是每个子进程在结束时都要经过的阶段。
    • 如果子进程在exit()之后,父进程没有来得及处理,这时用ps命令就能看到子进程的状态是“Z”。
    • 如果父进程能及时 处理,可能用ps命令就来不及看到子进程的僵尸状态,但这并不等于子进程不经过僵尸状态。
    • 如果父进程在子进程结束之前退出,则子进程将由init接管。
    • init将会以父进程的身份对僵尸状态的子进程进行处理。

[3] 示例

import multiprocessing
import time


def work(name):
    print(f'{name} is starting .... ')
    time.sleep(2)
    print(f'{name} is ending .... ')


def main():
    for i in range(3):
        task = multiprocessing.Process(
            target=work,
            args=(f'task_{i}',)
        )
        task.start()


if __name__ == '__main__':
    print(f'main process starting ...')
    main()
    print(f'main process ending ...')
   

	'''
    main process starting ...
    main process ending ...
    task_0 is starting ....
    task_1 is starting ....
    task_2 is starting ....
    task_0 is ending ....
    task_2 is ending ....
    task_1 is ending ....
    '''

【3】孤儿进程(无害)

[1] 什么是孤儿进程

  • 孤儿进程则是指父进程在子进程终止之前就已经退出了,导致子进程失去了与父进程通信的能力。
  • 这些孤儿进程将被 init 进程接管
  • init 进程会等待它的状态信息并释放它的系统资源。

[2] 示例

import os
import sys
import time

if __name__ == '__main__':
    pid = os.getpid()
    ppid = os.getppid()
    print('我是父进程 :>>> ', 'pid', pid, 'ppid', ppid)
    pid = os.fork()
    # 执行pid=os.fork()则会生成一个子进程
    # 返回值pid有两种值:
    #    如果返回的pid值为0,表示在子进程当中
    #    如果返回的pid值>0,表示在父进程当中
    if pid > 0:
        print('父进程终止')
        sys.exit(0)

    # 保证主线程退出完毕
    time.sleep(1)
    print('我是子进程 :>>>> ', os.getpid(), os.getppid())

    # 子进程已经被pid为1的init进程接收了
    # 所以僵尸进程在这种情况下是不存在的,存在只有孤儿进程而已
    # 孤儿进程声明周期结束自然会被init来销毁。
    # 我是父进程 :>>>  pid 86270 ppid 61564
    # 父进程终止

【二】守护进程

【1】什么是守护进程

  • 守护进程 (daemon) 是在计算机系统启动时就已经运行,并且一直在后台运行的一类特殊进程。
  • 它们通常不与用户直接交互,也不接受标准输入和输出,而是在后台执行某种任务或提供某种服务。
  • 守护进程往往是由系统管理员手动启动的,它们可以在系统启动时自动启动,一直运行在后台,直到系统关闭或被停止。
  • 常见的守护进程包括网络服务 (如 web 服务器、邮件服务器、 ftp 服务器等)、日志记录系统 (如系统日志服务、应用程序日志服务等) 等。
  • 守护进程通常在后台运行,不需要用户交互,并且有较高的权限,因此编写守护进程需要特别注意安全性和稳定性。

[1] 主进程死亡,子进程未死亡

from multiprocessing import Process
import time


def task(name):
    print(f'总管:>>{name}>>正常存活')
    time.sleep(2)
    print(f'总管:>>{name}>>正常死亡')


if __name__ == '__main__':
    print(f'皇帝 :>>> Tom >>> 执掌江山')
    p = Process(target=task, args=('max',))
    # p = Process(target=task, kwargs={"name":"max"})

    p.start()

    print(f'皇帝 :>>> Tom >>> 寿终正寝')

    # 皇帝 :>>> Tom >>> 执掌江山
    # 皇帝 :>>> Tom >>> 寿终正寝
    # 总管:>>max>>正常存活
    # 总管:>>max>>正常死亡

[2] 主进程死亡,子进程必死亡

  • 正确用法
from multiprocessing import Process
import time


def task(name):
    print(f'总管:>>{name}>>正常存活')
    time.sleep(2)
    print(f'总管:>>{name}>>正常死亡')


if __name__ == '__main__':
    print(f'皇帝 :>>> Tom >>> 执掌江山')
    p = Process(target=task, args=('max',))
    # p = Process(target=task, kwargs={"name":"max"})

    # 将进程 p 设置成守护进程
    p.daemon = True

    p.start()

    print(f'皇帝 :>>> Tom >>> 寿终正寝')

    # 皇帝 :>>> Tom >>> 执掌江山
    # 皇帝 :>>> Tom >>> 寿终正寝

标签:__,task,name,print,pid,孤儿,进程,守护
From: https://www.cnblogs.com/chosen-yn/p/18216198

相关文章

  • postgressq——四种进程间锁(4)
    进程间锁在PostgreSQL里有四种类型的进程间锁:Spinlocks:自旋锁,其保护的对象一般是数据库内部的一些数据结构,是一种轻量级的锁。LWLocks:轻量锁,也是主要用于保护数据库内部的一些数据结构,支持独占和共享两种模式。Regularlocks:又叫heavyweightlocks,也就是我们常说的表锁......
  • Java 进程 CPU 占用过高问题排查
    1.Java进程CPU占用过高问题排查1.1.运行环境1.2.定位CPU占用高的进程1.3.定位CPU占用高的线程1.4.将线程ID转换为十六进制1.5.找到线程对应的栈信息1.5.1.使用jstack1.5.2.使用jcmd1.5.3.使用arthas1.5.4.使用jattach1.Java进程CPU......
  • 操作系统实验二 短作业优先进程调度算法
    实验二短作业优先进程调度算法实验内容编写程序,模拟实现短作业优先进程调度算法。从测试文件读入进程相关信息,然后给出不同进程调度算法下,进程的运行次序情况。测试数据文件格式:测试数据文件包括n行测试数据,分别描述n个进程的相关信息。每行测试数据包括四个字段,各个字......
  • 原子上下文、进程上下文和中断上下文
    进程上下文、中断上下文及原子上下文转自:进程上下文、中断上下文及原子上下文_知秋一叶-CSDN博客​谈论进程上下文、中断上下文、原子上下文之前,有必要讨论下两个概念:a--上下文​上下文是从英文context翻译过来,指的是一种环境。相对于进程而言,就是进程执行时的环......
  • c# 通过 SendMessage 实现跨进程数据通信
    usingSystem;usingSystem.Collections.Generic;usingSystem.ComponentModel;usingSystem.Data;usingSystem.Drawing;usingSystem.Linq;usingSystem.Text;usingSystem.Windows.Forms;usingSystem.IO.MemoryMappedFiles;usingSystem.Runtime.InteropServices......
  • 【Python并发编程指南】多线程、多进程与异步编程比较与选择
    ......
  • 测试进程A是否可以执行关联的响应接口
    设计两个程序,要求进程A中自定义信号SIGUSR1的响应接口,要求进程B每隔一段时间向进程A就发送SIGUSR1信号,测试进程A是否可以执行关联的响应接口。/*******************************************************************************************************@filename: :pro......
  • 进程和线程
    何为进程:进程是程序的一次执行过程,是系统运行程序的基本单位,因此进程是动态的。系统运行一个程序即是一个进程从创建,运行到消亡的过程。当一个程序被运行,从磁盘加载这个程序的代码至内存,这时就开启了一个进程。进程就可以视为程序的一个实例。站在操作系统的角度,进程是程......
  • vb.net 利用APi 、句柄,通过GetWindowThreadProcessId 获得窗口所在进程ID和线程ID 结
    '''<summary>'''声明'''</summary>'''<paramname="hwnd"></param>'''<paramname="lpdwProcessId"></param>......
  • C#的奇技淫巧:利用WinRM来远程操控其他服务器上的进程
     前言:有时候远程服务器的进程你想偷偷去围观一下有哪些,或者对一些比较调皮的进程进行封杀,或者对一些自己研发的服务进行远程手动启动或者重启等,又不想打开远程桌面,只想悄咪咪地执行,那也许下面的文章会对你有启发。前提条件确保远程服务器(服务端)已启用WinRM。在远程服务器上运......