[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
- 提問的藝術