Page

[多进程]php创建多进程的简单示例

798Anson17-11-23


使用到的系统函数:pcntl_fork以及pcntl_wait

pcntl_fork

(PHP 4 >= 4.1.0, PHP 5, PHP 7)

pcntl_fork — 在当前进程当前位置产生分支(子进程)。译注:fork是创建了一个子进程,父进程和子进程 都从fork的位置开始向下继续执行,不同的是父进程执行过程中,得到的fork返回值为子进程 号,而子进程得到的是0。

成功时,在父进程执行线程内返回产生的子进程的PID,在子进程执行线程内返回0。失败时,在 父进程上下文返回-1,不会创建子进程,并且会引发一个PHP错误。

pcntl_wait

(PHP 5, PHP 7)

pcntl_wait — 等待或返回fork的子进程状态

wait函数刮起当前进程的执行直到一个子进程退出或接收到一个信号要求中断当前进程或调用一个信号处理函数。 如果一个子进程在调用此函数时已经退出(俗称僵尸进程),此函数立刻返回。子进程使用的所有系统资源将 被释放。关于wait在您系统上工作的详细规范请查看您系统的wait(2)手册。


代码:

<?php

$pid = pcntl_fork();

if($pid == -1){
    exit('无法创建子进程');

}else if($pid){
    echo '我是父进程,我刚创建的子进程号为:'.$pid."\n";

}else{
    echo '我是子进程,$pid返回的是:'.$pid."\n";
}

while(1);


解释:

首先使用pcntl_fork创建一个子进程,如果$pid返回-1则代表创建失败,否则成功;成功之后父子进程都会执行fork下面代码语句,也就是if判断;父进程的$pid得到的是子进程的进程号,所以父进程执行的是else if里面的语句,而子进程中$pid返回的是0,所以就进入到else的语句中。


while(1)的作用是让进程一直运行


运行效果:子进程号为6152

blob.png


用ps aux|grep php查看进程,可以看到父进程号为6142,子进程号为6152


blob.png



这里我们引入一个知识点:僵尸进程



什么是僵尸进程


在UNIX 系统中,一个进程结束了,但是他的父进程没有等待(调用wait / waitpid)他,那么他将变成一个僵尸进程。当用ps命令观察进程的执行状态时,看到这些进程的状态栏为defunct。僵尸进程是一个早已死亡的进程,但在进程表(processs table)中仍占了一个位置(slot)。


但是如果该进程的父进程已经先结束了,那么该进程就不会变成僵尸进程。因为每个进程结束的时候,系统都会扫描当前系统中所运行的所有进程,看看有没有哪个进程是刚刚结束的这个进程的子进程,如果是的话,就由Init进程来接管他,成为他的父进程,从而保证每个进程都会有一个父进程。而Init进程会自动wait其子进程,因此被Init接管的所有进程都不会变成僵尸进程。



我来测试一下,把子进程6152kill掉,用ps查看进程,看到6152变成了defunct僵尸进程

kill 6152


blob.png


为了阻止子进程变成僵尸进程,我们要在父进程中调用pcntl_wait等待子进程


代码改为:

<?php

$pid = pcntl_fork();

if($pid == -1){
    exit('无法创建子进程');

}else if($pid){

    pcntl_wait($status);  //等待子进程中断,防止子进程成为僵尸进程。
    
}else{
    echo '我是子进程,$pid返回的是:'.$pid."\n";
}

while(1);


这时候我再重新测试一下


blob.png

blob.png

blob.png


备注:查看父进程下的所有子进程命令

pstree -p 父进程id


引用自:

http://php.net/manual/zh/function.pcntl-fork.php#refsect1-function.pcntl-fork-returnvalues

http://php.net/manual/zh/function.pcntl-wait.php

http://hanover.iteye.com/blog/881972



来自ansion博客 

http://www.tp0.top

2017-11-23 11:09:04