守护进程, 孤儿进程, 僵尸进程与waitpid

守护进程是在一类脱离终端在后台执行的程序, 通常以d结尾, 随系统启动, 其父进程(ppid)通常是init进程

一般要让当前程序以守护进程形式运行, 在命令后加&并重定向输出即可

$ python someprogram.py > /dev/null 2>&1 &
或者使用nohup也可以
这是直接运行程序的方式, 如果是用具体语言代码的形式来实现呢, 首先看一下守护进程的实现方式

  1. 创建子进程, 父进程退出
    父进程先于子进程退出会造成子进程成为孤儿进程,而每当系统发现一个孤儿进程时,就会自动由1号进程(init)收养它,这样,原先的子进程就会变成init进程的子进程

  2. 在子进程中创建新会话

更改工作目录到/, 以便umount一个文件系统

  1. 重设文件权限掩码, 以便拥有完全的写的权限, 即重设继承来的默认文件权限值

  2. 调用setuid, 让当前进程成为新的会话组长和进程组长

  3. 执行第二次fork
    关闭文件描述符, 一般是输入/输出和错误输出, 重定向到/dev/null

py代码
https://gist.github.com/jamiesun/3097215

上面守护进程的生成步骤中涉及到了孤儿进程
任何孤儿进程产生时都会立即为系统进程init自动接收为子进程,这一过程也被称为“收养”. 但由于创建该进程的进程已不存在,所以仍应称之为“孤儿进程”

与之相关的一个概念就是 僵尸进程了. 当子进程退出时, 父进程需要wait/waitpid系统调用来读取子进程的exit status, 然后子进程被系统回收. 如果父进程没有wait的话, 子进程将变成一个"僵尸进程", 内核会释放这个子进程所有的资源,包括打开的文件占用的内存等, 但在进程表中仍然有一个PCB, 记录进程号和退出状态等信息, 并导致进程号一直被占用, 而系统能使用的进程号数量是有限的(可以用ulimit查看相关限制), 如果产生大量僵尸进程的话, 将因为没有可用的进程号而导致系统不能产生新的进程

因此很多自带重启功能的服务实现就是用wait/waitpid实现的.
waitpid()会暂时停止目前进程的执行,直到有信号来到或子进程结束
比如tornado中fork多进程就是这样, 监控子进程的运行状态, 当其意外退出时自动重启子进程

def fork_processes(num_processes, max_restarts=100):
"""Starts multiple worker processes.

If ``num_processes`` is None or  0, we fork thatspecific number of sub-processes.Since we use processes and not threads, there is no shared memorybetween any server code.Note that multiple processes are not compatible with the autoreloadmodule (or the ``autoreload=True`` option to `tornado.web.Application`which defaults to True when ``debug=True``).When using multiple processes, no IOLoops can be created orreferenced until after the call to ``fork_processes``.In each child process, ``fork_processes`` returns its *task id*, anumber between 0 and ``num_processes``.  Processes that exitabnormally (due to a signal or non-zero exit status) are restartedwith the same id (up to ``max_restarts`` times).  In the parentprocess, ``fork_processes`` returns None if all child processeshave exited normally, but will otherwise only exit by throwing anexception."""global _task_idassert _task_id is Noneif num_processes is None or num_processes  max_restarts:        raise RuntimeError("Too many child restarts, giving up")    new_id = start_child(id)    if new_id is not None:        return new_id# All child processes exited cleanly, so exit the master process# instead of just returning to right after the call to# fork_processes (which will probably just start up another IOLoop# unless the caller checks the return value).sys.exit(0)

参考: http://bbs.chinaunix.net/thread-4071026-1-1.html

关键字:Python, linux

版权声明

本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处。如若内容有涉嫌抄袭侵权/违法违规/事实不符,请点击 举报 进行投诉反馈!

立即
投稿

微信公众账号

微信扫一扫加关注

返回
顶部