对于用PHP进行多进程并发编程,不可避免要遇到僵尸进程的问题。

僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程(zombie)进程。任何进程在退出前(使用exit退出) 都会变成僵尸进程(用于保存进程的状态等信息),然后由init进程接管。如果不及时回收僵尸进程,那么它在系统中就会占用一个进程表项,如果这种僵尸进程过多,最后系统就没有可以用的进程表项,于是也无法再运行其它的程序。
 
方法一:
父进程通过pcntl_wait和pcntl_waitpid等函数等待子进程结束
 $pid = pcntl_fork();

 if($pid == -1) {
die('fork error');
} else if ($pid) {
//父进程阻塞着等待子进程的退出
//pcntl_wait($status); //pcntl_waitpid($pid, $status); //非阻塞方式
//pcntl_wait($status, WNOHANG); //pcntl_waitpid($pid, $status, WNOHANG);
} else {
sleep(3);
echo "child \r\n";
exit;
}
方法二:
可以用signal函数为SIGCHLD安装handler,因为子进程结束后,父进程会收到该信号,可以在handler中调用pcntl_wait或pcntl_waitpid来回收。
 <?php
declare(ticks = 1); //信号处理函数
function sig_func() {
echo "SIGCHLD \r\n";
pcntl_wait($status); //pcntl_waitpid(-1, $status); //非阻塞
//pcntl_wait($status, WNOHANG);
//pcntl_waitpid(-1, $status, WNOHANG);
} pcntl_signal(SIGCHLD, 'sig_func'); $pid = pcntl_fork(); if($pid == -1) {
die('fork error');
} else if ($pid) {
sleep(10);
} else {
sleep(3);
echo "child \r\n";
exit;
}
如果子进程还没有结束时,父进程就结束了,那么init进程会自动接手这个子进程,进行回收。
如果父进程是循环,又没有安装SIGCHLD信号处理函数调用wait或waitpid()等待子进程结束。那么子进程结束后,没有回收,就产生僵尸进程了。
例如:
<?php
$pid = pcntl_fork(); if($pid == -1) {
die('fork error');
} else if ($pid) {
for(;;) {
sleep(3);
}
} else {
echo "child \r\n";
exit;
}

父进程是个死循环,也没有安装SIGCHLD信号处理函数,子进程结束后。我们通过如下命令查看  > ps -A -o stat,ppid,pid,cmd | grep -e '^[Zz]'

会发现一个僵尸进程。
 
代码改进一下:
 <?php
declare(ticks = 1); //信号处理函数
function sig_func() {
echo "SIGCHLD \r\n"; pcntl_waitpid(-1, $status, WNOHANG);
} pcntl_signal(SIGCHLD, 'sig_func'); $pid = pcntl_fork(); if($pid == -1) {
die('fork error');
} else if ($pid) {
for(;;) {
sleep(3);
}
} else {
echo "child \r\n";
exit;
}
当子进程结束后,再通过命令查看时,我们发现这时就没有僵尸进程了,这说明父进程对它进行了回收。
 
方法三:
如果父进程不关心子进程什么时候结束,那么可以用pcntl_signal(SIGCHLD, SIG_IGN)通知内核,自己对子进程的结束不感兴趣,那么子进程结束后,内核会回收,并不再给父进程发送信号。
 <?php
declare(ticks = 1); pcntl_signal(SIGCHLD, SIG_IGN); $pid = pcntl_fork(); if($pid == -1) {
die('fork error');
} else if ($pid) {
for(;;) {
sleep(3);
}
} else {
echo "child \r\n";
exit;
}
当子进程结束后,SIGCHLD信号并不会发送给父进程,而是通知内核对子进程进行了回收。
 
方法四:
通过pcntl_fork两次,也就是父进程fork出子进程,然后子进程中再fork出孙进程,这时子进程退出。那么init进程会接管孙进程,孙进程退出后,init会回收。不过子进程还是需要父进程进行回收。我们把业务逻辑放到孙进程中执行,父进程就不需要pcntl_wait或pcntl_waitpid来等待孙进程(即业务进程)。
 <?php
$pid = pcntl_fork(); if($pid == -1) {
die('fork error');
} else if ($pid) {
//父进程等待子进程退出
pcntl_wait($status);
echo "parent \r\n";
} else {
//子进程再fork一次,产生孙进程
$cpid = pcntl_fork();
if($cpid == -1) {
die('fork error');
} else if ($cpid) {
//这里是子进程,直接退出
echo "child \r\n";
exit;
} else {
//这里是孙进程,处理业务逻辑
for($i = 0; $i < 10; ++$i) {
echo "work... \r\n";
sleep(3);
}
}
}

子进程退出后,父进程回收子进程,孙进程继续业务逻辑的处理。当孙进程也执行完毕退出后,init回收孙进程。

php多进程防止出现僵尸进程的更多相关文章

  1. PHP多进程编之僵尸进程问题

    上一篇说到了使用pcntl_fork函数可以让PHP实现多进程并发或者异步处理的效果.那么问题是我们产生的进程需要去控制,而不能置之不理.最基本的方式就是fork进程和杀死进程. 通过利用pcntl_ ...

  2. php多进程pcntl学习-僵尸进程

    上个月写的文章,php多进程pcntl学习(一)现在发现并不完整,因为虽然提到了关闭子进程,但是并没有回收子进程,简单的说就是当子进程比父进程先退出,而父进程没对其做任何处理的时候,子进程将会变成僵尸 ...

  3. PHP多进程编程之僵尸进程问题

    上一篇说到了使用pcntl_fork函数可以让PHP实现多进程并发或者异步处理的效果.那么问题是我们产生的进程需要去控制,而不能置之不理.最基本的方式就是fork进程和杀死进程. 通过利用pcntl_ ...

  4. php多进程 防止出现僵尸进程

    对于用PHP进行多进程并发编程,不可避免要遇到僵尸进程的问题. 僵尸进程是指的父进程已经退出,而该进程dead之后没有进程接受,就成为僵尸进程(zombie)进程.任何进程在退出前(使用exit退出) ...

  5. 多进程wait、僵尸进程、孤儿进程、prctl

    1.概念 1.孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程.孤儿进程将被init进程(进程号为1)所收养,从而保证每个进程都会有一个父进程.而Init进程会自 ...

  6. PHP的多进程--防止僵尸进程(转)

    原文地址:http://twei.site/2017/08/08/PHP%E7%9A%84%E5%A4%9A%E8%BF%9B%E7%A8%8B-%E9%98%B2%E6%AD%A2%E5%83%B5 ...

  7. Linux 网络编程详解六(多进程服务器僵尸进程解决方案)

    小结:在点对点p2p程序中,服务器端子程序退出,子进程会主动发送信号,关闭父进程,但是这种模式导致服务器只能支持一个客户端连接,本章节中使用新的框架,子进程退出,不主动发送信号关闭父进程,而是父进程安 ...

  8. python学习笔记—— 多进程中的 孤儿进程和僵尸进程

    1 基本概述 1.1 孤儿进程和僵尸进程 父进程创建子进程后,较为理想状态是子进程结束,父进程回收子进程并释放子进程占有的资源:而实际上,父子进程是异步过程,两者谁先结束是无顺的,一般可以通过父进程调 ...

  9. C/C++网络编程8——多进程服务器端之销毁僵尸进程

    上一节提到,当子进程执行结束,父进程还在执行,在父进程结束之前子进程会成为僵尸进程,那么怎么销毁僵尸进程呢?父进程主动接收子进程的返回值. 销毁僵尸进程的方法: 1:使用wait函数 2:使用wait ...

随机推荐

  1. 温故之--Linux 初始化 init 系统

    参选URL: http://www.ibm.com/developerworks/cn/linux/1407_liuming_init1/index.html 本系列一共三篇,看完记住,那水平就不一样 ...

  2. Colored Sticks (并查集+Trie + 欧拉路)

    Time Limit: 5000MS   Memory Limit: 128000K Total Submissions: 37340   Accepted: 9796 Description You ...

  3. N天学习一个Linux命令之free

    用途 查看系统内存(物理/虚拟/缓存/共享)使用情况 用法 free [-b | -k | -m | -g | -h] [-o] [-s delay ] [-c count ] [-a] [-t] [ ...

  4. N天学习一个Linux命令之mkdir

    前言 暂无 用途 用于新建目录 常用参数 1.设置目录权限-m, --mode=MODE 2.递归创建目录(父目录不存在时,也创建)-p, --parents 3.其它-v, --verbose pr ...

  5. Android开发之PullToRefresh的Click点击事件的监听实现长按删除Item

    本文为原创博客.出自http://blog.csdn.net/minimicall 到今天为止,搜芽的卖家版本号应该来说已经基本完毕.攻坚克难的一路过来.速度也控制的比較好. 项目过程进度 从任务分配 ...

  6. MFC小程序003------MFC使用WebBrowser组件,在对话框中创建滚动视图,动态创建一个静态文本控件并设置鼠标单击的消息响应

    MFC小程序截图: 一.在MFC中简单使用WebBrowser的ActiveX插件的方法: 见博文:  http://blog.csdn.net/supermanking/article/detail ...

  7. 【Git学习笔记】用git pull取回远程仓库某个分支的更新,再与本地的指定分支自动merge【转】

    本文转载自:http://blog.csdn.net/liuchunming033/article/details/45367629 git pull的作用是,从远程库中获取某个分支的更新,再与本地指 ...

  8. hdu4738Caocao's Bridges

    什么?有人要炸我的桥?!D飞他(心疼周瑜大都督) 这个就是求割边/桥了. #include<cstdio> #include<iostream> #include<cst ...

  9. bzoj 4198 [ Noi 2015 ] 荷马史诗 —— 哈夫曼编码(k叉哈夫曼树)

    题目:https://www.lydsy.com/JudgeOnline/problem.php?id=4198 第一次写哈夫曼树!看了很多博客. 哈夫曼树 & 哈夫曼编码:https://w ...

  10. BZOJ 4514 费用流

    思路: 懒得写了 http://blog.csdn.net/werkeytom_ftd/article/details/51277482 //By SiriusRen #include <que ...