• Linux下fork机制详解(以PHP为例)


    参考:https://blog.csdn.net/jason314/article/details/5640969

    1.fork简介

    • 一个进程,包括代码、数据和分配给进程的资源。fork()函数通过系统调用创建一个与原来进程几乎完全相同的进程,也就是两个进程可以做完全相同的事,但如果初始参数或者传入的变量不同,两个进程也可以做不同的事。
    • 一个进程调用fork()函数后,系统先给新的进程分配资源,例如存储数据和代码的空间。然后把原来的进程的所有值都复制到新的新进程中,只有少数值与原来的进程的值不同。相当于克隆了一个自己。
    • fork调用的一个奇妙之处是它仅仅被调用一次,却能够返回两次,它可能有三种不同的返回值:
      • 在父进程中,fork返回新创建子进程的进程ID;
      • 在子进程中,fork返回0;
      • 如果出现错误,fork返回一个负值;
    • 关于fork出来的进程PID不同的解释:
      • 进程形成了链表,父进程的pid(p 意味point)指向子进程的进程id。
      • 子进程没有子进程,所以其fpid为0。
      • 可以通过fork返回的值来判断当前进程是子进程还是父进程。
    • 父子进程执行没有固定的先后顺序,哪个进程先执行要看系统的进程调度策略
    <?php
    
    /**
     * fork_demo.php
     * @desc:单进程
     */
    $count= 0;
    $fpid = pcntl_fork(); 
    if ($fpid < 0) { 
        echo "error in fork!"; 
    } else if ($fpid == 0) {
        //子进程执行空间
        //getmypid()可在Windows和Linux上执行,获取当前进程PID
        echo sprintf("i am the child process, my process id is %d
    ",getmypid()); 
        $count++;
    } else {
        //父进程执行空间
        //posix_getpid()只能在Linux上执行,获取当前进程PID
        echo sprintf("i am the parent process, my process id is %d
    ",posix_getpid()); 
        $count++;
    }
    echo sprintf("the count of result: %d
    ", $count);
    
    ?>

     执行结果:

     

    2.fork进阶

    <?php
    /**
     * fork_demo2.php
     * @desc:多进程
     */
    define('FORK_NUMS', 2);
    
    echo "i son/pa ppid  pid   fpid
    ";
    //ppid 指当前进程的父进程
    //pid指当前进程
    //fpid指fork返回给当前进程的值
    for($i=0; $i<FORK_NUMS; $i++){
        $fpid = pcntl_fork();
        if($fpid<0){
            echo "fork error";
        }else if($fpid == 0){
            $format = "%d child  %5d %5d %5d
    ";
            echo sprintf($format, $i, posix_getppid(), posix_getpid(), $fpid);
        }else{
            $format = "%d parent %5d %5d %5d
    ";
            echo sprintf($format, $i, posix_getppid(), posix_getpid(), $fpid);
        }
    }

     执行结果:

     

    代码解析:
    1.第一步:在父进程中,指令执行到for循环中,$i=0,接着执行fork,系统中出现两个进程,分别是p33584和p33585(后面我都用pxxxx表示进程id为xxxx的进程)。可以看到父进程p33584的父进程是p31166,子进程p33585的父进程正好是p33584。我们用一个链表来表示这个关系:
      p31166->p33584->p33585
      第一次fork后,p33584(父进程)的变量为$i=0,$fpid=33585(fork函数在父进程中返向子进程pid)
    
    2.第二步:假设父进程p33584先执行,当进入下一个循环时,$i=1,接着执行fork,系统中又新增一个进程p33586,对于此时的父进程,p31166->p33584(当前进程)->p33585(被创建的子进程)。
      对于子进程p33585,执行完第一次循环后,$i=1,接着执行fork,系统中新增一个进程p33587,对于此进程,p33584->p33585(当前进程)->p33587(被创建的子进程)。从输出可以看到p33585原来是p33584的子进程,现在变成p33587的父进程。父子是相对的,这个大家应该容易理解。只要当前进程执行了fork,该进程就变成了父进程了,就打印出了parent。
    
    3.第三步:第二步创建了两个进程p33586,p33587,这两个进程执行完sprintf函数后就结束了,因为这两个进程无法进入第三次循环,无法fork,其他进程也是如此。

    4.程序最终产生了3个子进程,执行过6次sprintf()函数。

    5.流程图如下:
    
    


  • 相关阅读:
    高德地图
    微信小程序蓝牙
    微信小程序请求封装
    create-react-app配置less
    浏览器渲染原理及流程
    输入网址到呈现网页发生的过程
    cookie的理解
    浏览器本地存储
    cookie,localStorage,sessionStorage区别
    关于this指向
  • 原文地址:https://www.cnblogs.com/yueyun00/p/10238351.html
Copyright © 2020-2023  润新知