[TOC]
# 僵尸进程
******
僵尸进程是当前子进程比父进程先结束,而父进程又没有回收子进程,释放子进程占用的资源,此时子进程将成为一个僵尸进程。
在 unix 进程管理中,如果你新开的子进程运行结束,父进程将会收到一个 SIGCHLD 信号,子进程成为僵尸进程(保存了进程的状态等信息),等待父进程的处理,如果父进程一直不处理,该进程将会一直存在,占用系统进程表项,如果僵尸过多,导致系统没有可用的进程表项,于是再也无法运行其他的程序。
> 为了更容易理解,本文使用 pcntl 扩展进行进程管理。
例如:
```php
<?php
$num = 1;
$str = "EasySwoole,Easy学swoole\n";
$pid = pcntl_fork();
if ($pid > 0) { // 主进程代码
echo "我是主进程,id是" . getmypid() . ",子进程的pid是{$pid}\n";
// 启用异步信号处理
pcntl_async_signals(true);
// 安装一个信号处理器 SIGCHLD 标识子进程结束或停止的信号
pcntl_signal(SIGCHLD, function () {
echo '子进程退出了,请及时处理' . PHP_EOL;
});
while (1) { // 主进程一直不退出
sleep(1);
}
} elseif ($pid == 0) {
echo "我是子进程,我的pid是" . getmypid() . "\n";
} else {
echo "我是主进程,我慌得一批,开启子进程失败\n";
}
```
使用 ps 查看僵尸进程:
```shell
ps -A -ostat,ppid,pid,cmd | grep -e '^[Zz]'
```
输出:
```shell
Z+ 1405 1406 [php] <defunct>
```
> 当主进程退出之后, 子进程将会被 init 接管并处理。
<br />
# 回收僵尸进程
## 回收僵尸进程
### 通过 pcntl_wait 和 pcntl_waitpid 等函数等待子进程结束
```php
<?php
$pid = pcntl_fork();
if ($pid == -1) {
die('fork error');
} elseif ($pid > 0) {
// 父进程阻塞着等待子进程的退出
/*pcntl_wait($status); // 等待或返回fork的子进程状态
pcntl_waitpid($pid, $status); // 等待或返回fork的子进程状态
*/
// 非阻塞方式
// WNOHANG 如果没有子进程退出立刻返回。
/*pcntl_wait($status, WNOHANG);
pcntl_waitpid($pid, $status, WNOHANG); */
} else {
sleep(3);
echo "child \r\n";
exit;
}
```
<br />
### 通过 signal 函数为 SIGCHLD 安装 handler,因为子进程结束后,父进程会收到该信号,可以在 handler 中调用 pcntl_wait 或 pcntl_waitpid 来回收。
```php
<?php
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, function () {
echo "SIGCHLD \r\n";
// 阻塞方式
pcntl_wait($status);
// pcntl_waitpid(-1, $status);
// 非阻塞
// pcntl_wait($status, WNOHANG);
// pcntl_waitpid(-1, $status, WNOHANG);
});
$pid = pcntl_fork();
if ($pid == -1) {
die('fork error');
} else if ($pid) {
sleep(10);
} else {
sleep(3);
echo "child \r\n";
exit;
}
```
<br />
### 忽略掉子进程结束信号,交给 init 进程管理
```php
<?php
pcntl_async_signals(true);
pcntl_signal(SIGCHLD, SIG_IGN);
$pid = pcntl_fork();
if ($pid == -1) {
die('fork error');
} else if ($pid > 0) {
while(1) {
sleep(1);
}
} else {
sleep(3);
echo "child \r\n";
exit;
}
```
- 引言
- Introduction
- 运行模式
- php-fpm
- php-cli
- 基础介绍
- 网络协议
- ip
- tcp
- tcp
- http
- webSocket
- udp
- port端口
- 会话管理
- cookie
- session
- api/token
- linux基础
- lnmp安装
- 命令
- 进程管理
- 扩展安装
- 端口监控
- 防火墙说明
- php7.0
- 部分新特性
- php回调/闭包
- 回调事件
- 闭包/匿名函数
- php多进程
- 多进程开启
- 进程通信
- 进程信号
- 僵尸进程
- 孤儿进程
- 守护进程
- 同步/异步
- 阻塞/非阻塞
- 协程
- Swoole
- 初始Swoole
- 运行机制
- 生命周期
- composer使用
- EasySwoole
- 设计理念
- 组件说明
- 运行过程
- demo
- 提问的艺术