本文实例讲述了php多进程并发编程防止出现僵尸进程的方法。分享给大家供大家参考,具体如下:
对于用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相关内容感兴趣的读者可查看本站专题:《PHP进程与线程操作技巧总结》、《PHP网络编程技巧总结》、《PHP基本语法入门教程》、《PHP数组(Array)操作技巧大全》、《php字符串(string)用法总结》、《php+mysql数据库操作入门教程》及《php常见数据库操作技巧汇总》
希望本文所述对大家PHP程序设计有所帮助。
僵尸进程 当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程的终止状态。 一个进程使用fork创建子进程,如果子进程退出,而父进程并没有调用wait或waitpid获取子进程的状态信息,那么子进程的进程描述符仍然保存在系统中。这种进程称之为僵尸进程。 理解了孤儿进程和僵尸进程,我们临时加了守护进程这一小节,守护进程就是后台进程吗?没那么简单。
上篇我整篇尬聊的都是 pcntl_fork(),只管 fork 生产,不管产后护理,实际上这样并不符合主流价值观,而且,操作系统本身资源有限,这样无限生产不顾护理,操作系统也会吃不消的。 孤儿进程是指父进程在 fork 出子进程后,自己先完了。这个问题很尴尬,因为子进程从此变得无依无靠、无家可归,变成了孤儿。用术语来表达就是,父进程在子进程结束之前提前退出,这些子进程将由 init(进程 ID 为
本文向大家介绍Shell脚本实现查杀子进程、僵尸进程,包括了Shell脚本实现查杀子进程、僵尸进程的使用技巧和注意事项,需要的朋友参考一下 核心服务器上跑了一堆的脚本、程序,难免有时候会出现僵尸进程,死不死活不活的在那里占用资源,最初只是写了个根据关键字查杀进程的linux shell脚本,后来发现很多时候进程死在那里的时候其实是内部调用子进程的时候出现了问题,这时候光杀父进程根本没解决根本问题。
问题内容: 我在前台启动了我的程序(守护程序),然后用杀死了它,但剩下一个僵尸,无法用杀死它。如何杀死僵尸进程? 如果僵尸是一个死进程(已被杀死),我如何将其从输出中删除? 问题答案: 僵尸已经死了,所以您无法杀死它。要清理僵尸,必须等待其父级等待,因此杀死父级应该可以消除僵尸。(父对象死后,僵尸将被pid 1继承,而pid 1将等待该僵尸并清除其在进程表中的条目。)如果守护程序正在生成成为僵尸的
问题内容: 我在Go中有一个应用程序,它可以重新路由二进制文件的STDIN和STDOUT,然后运行它们。简而言之,我正在做: 我注意到,只要在运行命令A时退出命令B的进程,它就会在进程表中变成僵尸进程。 这是一个例子: 如果commandB仍在运行时退出,为什么commandB会变成僵尸?我在Ubuntu 14上运行Go 1.5。 问题答案: 当某个进程退出时,无论正在运行什么其他进程,它 总是
更多面试题总结请看:【面试题】技术面试题汇总 进程的状态 基本状态 进程的基本状态:“就绪”、“执行”、“阻塞”。 就绪:进程已获得除处理机以外的所需资源,等待分配处理机资源 执行:进程正在占用处理机资源执行 阻塞:进程等待某种条件,在条件满足之前无法执行。如发起了 I/O 系统调用,会被阻塞,等待 I/O 中断发生 挂起 “挂起”是指将暂不执行的进程换出到外存,节省内存空间。 “挂起”和“阻塞”
问题内容: 维基百科说:“一个终止但从未被其父级等待的子进程变成了僵尸进程。” 我运行此程序: 这会创建一个僵尸进程,但我不明白为什么在这里创建了僵尸进程? 该程序的输出是 但是在这种情况下,为什么“子进程终止但没有被其父进程等待”呢? 问题答案: 在您的代码中,创建了僵尸(带有以下箭头的注释): 为什么?因为你从来没有上过。调用时,它将返回有关进程的事后信息,例如其退出代码。不幸的是,当进程退出
本文向大家介绍请你说一下僵尸进程?相关面试题,主要包含被问及请你说一下僵尸进程?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 1)正常进程 正常情况下,子进程是通过父进程创建的,子进程再创建新的进程。子进程的结束和父进程的运行是一个异步过程,即父进程永远无法预测子进程到底什么时候结束。 当一个进程完成它的工作终止之后,它的父进程需要调用wait()或者waitpid()系统调用取得子进程