PHP多进程学习(三)父进程与子进程的执行顺序,进程中共享数据

案例1


$pid = pcntl_fork();
 
if($pid == -1) {
     
    //错误处理:创建子进程失败时返回-1.
    die('fork error');
} else if ($pid) {
     
    //父进程会得到子进程号,所以这里是父进程执行的逻辑
    echo "parent \n";
    //等待子进程中断,防止子进程成为僵尸进程。
    pcntl_wait($status);
} else {
     
    //子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
    echo "child \n";
 
    exit;
}

上述代码会经过多次执行,分别输出parent和child

案例2


$pid = pcntl_fork();
 
if($pid == -1) {
     
    die('fork error');
} else if ($pid) {
     
    sleep(3);
    echo "parent \n";
    pcntl_wait($status);
} else {
     
    echo "child \n";
 
    exit;
}

结果是,很快输出了child,等待了接近3秒后,才输出parent。所以父进程和子进程的执行是相对独立的,没有先后之分。

pcntl_wait是:
会挂起当前进程,直到子进程退出,如果子进程在调用此函数之前就已退出,此函数会立刻返回。子进程使用的资源将被释放。

案例3


$pid = pcntl_fork();
 
if($pid == -1) {
     
    die('fork error');
} else if ($pid) {
     
    pcntl_wait ($status);
    echo "parent \n";
} else {
     
    sleep(3);
    echo "child \n";
 
    exit;
}

上述代码,我们可以看到,父进程执行pcntl_wait时就已经挂起,直到等待3秒后输出child,子进程退出后。父进程继续执行,输出parent。

案例4


define('FORK_NUMS', 3);
 
$pids = array();
 
for($i = 0; $i < FORK_NUMS; ++$i) {
     
    $pids[$i] = pcntl_fork();
    if($pids[$i] == -1) {
     
        die('fork error');
    } else if ($pids[$i]) {
     
        pcntl_waitpid($pids[$i], $status);
        echo "pernet \n";
    } else {
     
        sleep(3);
        echo "child id:" . getmypid() . " \n";
        exit;
    }
}

上述代码,我们创建3个子进程,父进程分别挂起等待子进程结束后,输出parent。

案例5


define('FORK_NUMS', 3);
 
$pids = array();
 
for($i = 0; $i < FORK_NUMS; ++$i) {
     
    $pids[$i] = pcntl_fork();
    if($pids[$i] == -1) {
     
        die('fork error');
    } else if ($pids[$i]) {
     
 
    } else {
     
        sleep(3);
        echo "child id:" . getmypid() . " \n";
        exit;
    }
}
 
foreach($pids as $k => $v) {
     
    if($v) {
     
        pcntl_waitpid($v, $status);
        echo "parent \n";
    }
}
//结果
child id:57579 
child id:57581 
child id:57580 
parent 
parent 
parent 

我们可以看到案例5的pcntl_waitpid函数放在了foreach中,foreach代码是在主进程中,也就是父进程的代码中。当执行foreach时,可能子进程已经全部执行完毕并退出。pcntl_waitpid会立刻返回,连续输出三个parent。
在子进程中,需通过exit来退出,不然会产生递归多进程,父进程中不需要exit,不然会中断多进程。

案例6


 
define('FORK_NUMS', 3);
 
$pids = array();
 
$fp = fopen('./test.log', 'wb');
$num = 1;
 
for($i = 0; $i < FORK_NUMS; ++$i) {
     
    $pids[$i] = pcntl_fork();
    if($pids[$i] == -1) {
     
        die('fork error');
    } else if ($pids[$i]) {
     
 
 
    } else {
     
        for($i = 0; $i < 5; ++$i) {
     
 
            flock($fp, LOCK_EX);
            fwrite($fp, getmypid() . ' : ' . date('Y-m-d H:i:s') . " : {
       $num} \r\n");
 
            flock($fp, LOCK_UN);
            echo getmypid(), ": success \r\n";
            ++$num;
        }
        exit;
    }
}
 
foreach($pids as $k => $v) {
     
    if($v) {
     
        pcntl_waitpid($v, $status);
    }
}
 
fclose($fp);
//结果 
57641: success 
57641: success 
57641: success 
57641: success 
57641: success 
57642: success 
57642: success 
57642: success 
57642: success 
57642: success 
57643: success 
57643: success 
57643: success 
57643: success 
57643: success 

//test.log  日志内容  
57641 : 2018-02-02 15:55:48 : 1 
57641 : 2018-02-02 15:55:48 : 2 
57641 : 2018-02-02 15:55:48 : 3 
57641 : 2018-02-02 15:55:48 : 4 
57641 : 2018-02-02 15:55:48 : 5 
57642 : 2018-02-02 15:55:48 : 1 
57642 : 2018-02-02 15:55:48 : 2 
57642 : 2018-02-02 15:55:48 : 3 
57642 : 2018-02-02 15:55:48 : 4 
57642 : 2018-02-02 15:55:48 : 5 
57643 : 2018-02-02 15:55:48 : 1 
57643 : 2018-02-02 15:55:48 : 2 
57643 : 2018-02-02 15:55:48 : 3 
57643 : 2018-02-02 15:55:48 : 4 
57643 : 2018-02-02 15:55:48 : 5 

我们可以看到三个子进程的pid,它们分别执行了5次,时间几乎是在同时。但是$num的值并没像我们期望的那样从1-15进行递增。子进程中的变量是各自独立的,互不影响。子进程会自动复制父进程空间里的变量。

案例7


 
define('FORK_NUMS', 3);
 
$pids = array();
 
$fp = fopen('./test.log', 'wb');
$num = 1;
//共享内存段的key
$shmKey = 123;
//创建共享内存段
$shmId = shmop_open($shmKey, 'c', 0777, 64);
//写入数据到共享内存段
shmop_write($shmId, $num, 0);
 
for($i = 0; $i < FORK_NUMS; ++$i) {
     
    $pids[$i] = pcntl_fork();
    if($pids[$i] == -1) {
     
        die('fork error');
    } else if ($pids[$i]) {
     
 
        //阻塞,等待子进程退出
 
        //注意这里,如果是非阻塞的话,$num的计数会出现问题。
        pcntl_waitpid($pids[$i], $status);
    } else {
     
        //读取共享内存段中的数据
        $num = shmop_read($shmId, 0, 64);
        for($i = 0; $i < 5; ++$i) {
     
            fwrite($fp, getmypid() . ' : ' . date('Y-m-d H:i:s') . " : {
       $num} \r\n");
            echo getmypid(), ": success \r\n";
            //递增$num
            $num = intval($num) + 1;
        }
 
        //写入到共享内存段中
 
        shmop_write($shmId, $num, 0);
        exit;
    }
}
 
//shmop_delete不会实际删除该内存段,它将该内存段标记为删除。
shmop_delete($shmId);
shmop_close($shmId);
fclose($fp);
19923 : 2016-03-17 00:05:18 : 1
19923 : 2016-03-17 00:05:18 : 2
19923 : 2016-03-17 00:05:18 : 3
19923 : 2016-03-17 00:05:18 : 4
19923 : 2016-03-17 00:05:18 : 5
19924 : 2016-03-17 00:05:18 : 6
19924 : 2016-03-17 00:05:18 : 7
19924 : 2016-03-17 00:05:18 : 8
19924 : 2016-03-17 00:05:18 : 9
19924 : 2016-03-17 00:05:18 : 10
19925 : 2016-03-17 00:05:18 : 11
19925 : 2016-03-17 00:05:18 : 12
19925 : 2016-03-17 00:05:18 : 13
19925 : 2016-03-17 00:05:18 : 14
19925 : 2016-03-17 00:05:18 : 15

这样我们就在进程间共享了$num的数据。

你可能感兴趣的:(PHP,php)