设为首页 加入收藏

TOP

linux fork进程请谨慎多个进程/线程共享一个 socket连接,会出现多个进程响应串联的情况。(一)
2019-08-15 23:30:23 】 浏览:50
Tags:linux fork 进程 谨慎 多个 线程 共享 一个 socket 连接 出现 响应 串联 情况

昨天组内同学在使用php父子进程模式的时候遇到了一个比较诡异的问题

简单说来就是:因为fork,父子进程共享了一个redis连接、然后父子进程在发送了各自的redis请求分别获取到了对方的响应体。

 

复现示例代码:

testFork.php

 1 <?php
 2 require_once("./PowerSpawn.php");
 3 
 4 $ps              = new Forkutil_PowerSpawn();
 5 $ps->maxChildren = 10 ;
 6 $ps->timeLimit   = 86400;
 7 
 8 $redisObj = new Redis();
 9 $redisObj->connect('127.0.0.1','6379');
10 
11 // 主进程 --  查询任务列表并新建子进程
12 while ($ps->runParentCode()) {
13     echo "parent:".$redisObj->get("parent")."\n" ;
14         // 产生一个子进程
15         if ($ps->spawnReady()) {
16                 $ps->spawnChild();
17         } else {
18                 // 队列已满,等待
19                 $ps->Tick();
20         }
21 }
22 
23 // 子进程 -- 处理具体的任务
24 if ($ps->runChildCode()) {
25     echo "chlidren:".$redisObj->get("children")."\n" ;
26 }

 

PowerSpawn.php 主要用户进程fork管理工作

 <?php
/*
 * PowerSpawn
 *
 * Object wrapper for handling process forking within PHP
 * Depends on PCNTL package
 * Depends on POSIX package
 *
 * Author:      Don Bauer
 * E-Mail:      lordgnu@me.com
 *
 * Date:        2011-11-04
 */
declare(ticks = 1);

class Forkutil_PowerSpawn
{
    private     $myChildren;
    private     $parentPID;
    private     $shutdownCallback = null;
    private $killCallback = null;

    public      $maxChildren    =       10;             // Max number of children allowed to Spawn
    public      $timeLimit              =       0;              // Time limit in seconds (0 to disable)
    public      $sleepCount     =       100;            // Number of uSeconds to sleep on Tick()

    public      $childData;                                     // Variable for storage of data to be passed to the next spawned child
    public      $complete;

    public function __construct() {
        if (function_exists('pcntl_fork') && function_exists('posix_getpid')) {
            // Everything is good
            $this->parentPID = $this->myPID();
            $this->myChildren = array();
            $this->complete = false;

            // Install the signal handler
            pcntl_signal(SIGCHLD, array($this, 'sigHandler'));
        } else {
            die("You must have POSIX and PCNTL functions to use PowerSpawn\n");
        }
    }

    public function __destruct() {

    }

    public function sigHandler($signo) {
        switch ($signo) {
            case SIGCHLD:
                $this->checkChildren();
                break;
        }
    }

    public function getChildStatus($name = false) {
        if ($name === false) return false;
        if (isset($this->myChildren[$name])) {
            return $this->myChildren[$name];
        } else {
            return false;
        }
    }

    public function checkChildren() {
        foreach ($this->myChildren as $i => $child) {
            // Check for time running and if still running
            if ($this->pidDead($child['pid']) != 0) {
                // Child is dead
                unset($this->myChildren[$i]);
            } elseif ($this->timeLimit > 0) {
                // Check the time limit
                if (time() - $child['time'] >= $this->timeLimit) {
                    // Child had exceeded time limit
                    $this->killChild($child['pid']);
                    unset($this->myChildren[$i]);
                }
            }
        }
    }

    /**
     * 获取当前进程pid
     * @return int
     */
    public function myPID() {
        return posix_getpid();
    }

    /**
     * 获取父进程pid
     * @return int
     */
    public function myParent() {
        return posix_getppid();
    }

    /**
     * 创建子进程 并记录到myChildren中
     * @param bool $name
     */
    public function spawnChild($name = false) {
        $time = time();
        $pid = pcntl_fork();
        if ($pid) {
            if ($name !== false) {
                $this->myChildren[$name] = array('time'=>$time,'pid'=>$pid);
            } else {
                $this->myChildren[] = array('ti
首页 上一页 1 2 3 下一页 尾页 1/3/3
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇PHP 是如何做垃圾回收的 下一篇PHP在无限分类时注意的一些问题(..

最新文章

热门文章

Hot 文章

Python

C 语言

C++基础

大数据基础

linux编程基础

C/C++面试题目