你成功了,他妒嫉你;你失败了,他笑话你 [登录·注册]

吕滔博客

首页 开发 运维 工具 摄影

PHP多进程之pcntl扩展的使用详解

开发 memory发布于May 17, 2017 标签: PHP

安装

1.编译php源码时加入

--enable-pcntl

2.在现有的环境下新增加扩展

cd php-version/ext/pcntl  
phpize  
./configure && make && make install  
echo "extension=pcntl.so" >> /etc/php.ini  

3.Mac下用brew安装 例如我本地是php7.1.5

brew install php71-pcntl 

使用

header('content-type:text/html;charset=utf-8' );  
  
// 必须加载扩展  
if (!function_exists("pcntl_fork")) {  
    die("pcntl extention is must !");  
} 
pcntl_signal(SIGCHLD, SIG_IGN); //如果父进程不关心子进程什么时候结束,子进程结束后,内核会回收。  
$pid_dir = __dir__."/pid_files";
for($i=0; $i<3; $i++){
    $pid = pcntl_fork(); //创建子进程 
    if($pid == -1){
        //错误处理:创建子进程失败时返回-1.
        var_dump("fork failed");
    }
    if(!$pid){
        //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。  
        //子进程代码
        $pid = posix_getpid();
        $ppid = posix_getppid();
        $r = rand(0,100);  //随机数
        touch("$pid_dir/fork_child_process_{$i}_{$ppid}_{$pid}_{$r}");
        exit;
    }else{
        //父进程会得到子进程号,所以这里是父进程执行的逻辑  
        //如果不需要阻塞进程,而又想得到子进程的退出状态,则可以注释掉pcntl_wait($status)语句,或写成:  
        pcntl_wait($status,WNOHANG); //等待子进程中断,防止子进程成为僵尸进程。
    }
} 
$pid = posix_getpid();
$ppid = posix_getppid();
$r = rand(0,100); //随机数
touch("$pid_dir/fork_process_pid_{$ppid}_{$pid}_$r");

相关参数

pcntl_waitpid

等待或返回fork的子进程状态。
多进程的主进程创建了子进程,那主进程如何确认子进程的状态呢。 假如主进程需要根据子进程的状态做不同的处理呢, 这里的状态包括子进程被kill掉,或变成僵尸进程等。 pcntl_waitpid就可以获取子进程的状态码, 通过这个状态码, 就可知道子进程处于什么状态
他的用法:

int pcntl_waitpid ( int $pid , int &$status [, int $options = 0 ] )

返回的值可以是-1,0或者 >0的值, 如果是-1, 表示子进程出错, 如果>0表示子进程已经退出且值是退出的子进程pid,至于如何退出, 可以通过$status状态码反应。 那什么时候返回0呢, 只有在option 参数为 WNOHANG且子进程正在运行时0, 也就是说当设置了options=WNOHANG时, 如果子进程还没有退出, 此时pcntl_waitpid就会返回0
另外, 如果不设置这个参数为WNOHANG, pcntl_waitpid 就会阻塞运行, 直到子进程退出, 至于option的另外一个值WUNTRACED, 暂未理解, 不表

那么如何根据$status(状态码)判断进程是如何退出呢, 如下(参数都是$status)

pcntl_wifexited

这个函数可以根据$status 判断进程是否正常退出, 何为正常退出, 比如exit

pcntl_wexitstatus

这个函数仅在pcntl_wifexited 返回True(即正常退出)时有效, 且返回子进程退出的返回状态码, 这个返回状态码可以通过exit($s)的参数($s必须为整数时)定义

pcntl_wifsignaled

检查子进程状态码是否代表由于某个信号而中断, 比如是不是我们给他发送了term, int 等信号了

pcntl_wexitstatus

假如是发送信号而导致子进程中断, 那么这个信号是什么信号呢, 这个函数就是获取这个信号的

pcntl_wifstopped

仅当option选项为WUNTRACED时有效, 未理解, 不表

pcntl_wtermsig

同上

综合实例代码:

$res = pcntl_waitpid($pid, $status, WNOHANG);
//FileLog::log("pid is $pid; wait result is $res");
if($res == -1 || $res > 0){
    if(!pcntl_wifexited($status)){
        //进程非正常退出
        FileLog::log("service stop unusally; pid is $pid");
    }else{
        //获取进程终端的退出状态码;
        $code = pcntl_wexitstatus($status);
        FileLog::log("service stop code: $code;pid is $pid ");
    }

    if(pcntl_wifsignaled($status)){
        //不是通过接受信号中断
        FileLog::log("service stop not by signal;pid is $pid ");
    }else{
        $signal = pcntl_wtermsig($status);
        FileLog::log("service stop by signal $signal;pid is $pid");
    }
}

上面的这个代码就通过根据pcntl_waitpid的返回结果和状态码对子进程因为不同原因中断做了不同的处理

官方文档:http://php.net/manual/zh/book.pcntl.php

相关推荐

添加新评论

全部评论:已有 2 条评论

香港服务器

香港服务器2017-05-23 18:43:17 回复

很详细,学习了

上海代理记账

上海代理记账2017-05-19 16:53:34 回复

看起来代码有一些复杂的呀。。。

网站状态

  • 栏目分类:35个
  • 发布文章:1109篇
  • 用户评论:620条

最新回复

  • 香港服务器: 很详细,学习了
  • memory: 对,这个密钥最好是自己换一下。当然不嫌麻烦甚至可以考虑将密钥做到...
  • 小明明: 在加密的时候 秘钥固定不就可以机密了吗
  • 上海代理记账: 看起来代码有一些复杂的呀。。。
  • 香港云服务器: 站长不错,不错的干货
  • yet handsome: 我看了你的这个发现历史真的是惊人的相似,我们已经做到redis集...
  • memory: 好久不玩它们了,我的相关知识来自谷歌...
  • 于小鱼: 你好,想请教一些关于xen和kvm的问题。
  • memory: 如果将图片 base64_encode 后,再想取回以前的路径不...
  • 陈凌风: 我要区正常的路径显示怎么办?
  • genuiner: 牛逼
  • haitongz: 赞
  • memory: php64位? 这个我还真没有注意。。。回头再试试
  • Kngstr: 这个很简单,你用的PHP不是64位的,64位的dll只能在64位...
  • memory: 使用的是typecho.
  • GavinHsueh: 您好,我了解下您的博客是自己开发的么?看着很不错
  • 个人博客: 看看先
  • memory: 谢谢,已修正。
  • jrotty: 方法一中next后面少个'符号
  • daxia: mark