进程标识

一个程序被加载到内存中运行,系统会为这个进程分配相应的标识信息,比如 pid,ppid,uid,euid,pgid,sid,gid,egid…

进程查看命令

  • pstree 可看出进程间的关系 父子,兄弟;
  • ps -exj
  • ps -aux
  • ps

PID PPID PGID UID TTY STAT TIME COMMAND

laradock@3a6c2da5a07b:/var/www$ ps exj
   PPID     PID    PGID     SID TTY        TPGID STAT   UID   TIME COMMAND
      0      24      24      24 pts/1        495 Ss    1000   0:00 bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/larado
     24     495     495      24 pts/1        495 R+    1000  13:37 php demo4.php LC_ALL=en_US.UTF-8 NVM_DIR=/home/laradock/.nvm LS_COLORS=no=00:fi=00:
      0     496     496     496 pts/2       1051 Ss    1000   0:00 bash PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/home/larado
    496    1051    1051     496 pts/2       1051 R+    1000   0:00 ps exj LC_ALL=en_US.UTF-8 NVM_DIR=/home/laradock/.nvm LS_COLORS=no=00:fi=00:di=01;3

进程状态码

  • D uninterruptible sleep (usually IO)
  • I Idle kernel thread
  • R running or runnable (on run queue)
  • S interruptible sleep (waiting for an event to complete)
  • T stopped by job control signal
  • t stopped by debugger during the tracing
  • W paging (not valid since the 2.6.xx kernel)
  • X dead (should never be seen)
  • Z defunct (“zombie”) process, terminated but not reaped by its parent

打印进程标识

fprintf(STDOUT, "pid=%d\n", posix_getpid());                  // 进程自己的标识   PID
fprintf(STDOUT, "ppid=%d\n", posix_getppid());                // 父进程的标识     PPID
fprintf(STDOUT, "pgid=%d\n", posix_getpgrp());                // 进程组长标识     PGID
fprintf(STDOUT, "sid=%d\n", posix_getsid(posix_getpid()));    // 会话标识         SID
fprintf(STDOUT, "uid=%d\n", posix_getuid());                  // 用户标识         UID    当前登录用户,实际用户id
fprintf(STDOUT, "gid=%d\n", posix_getgid());                  // 组ID            GID
fprintf(STDOUT, "euid=%d\n", posix_geteuid());                // 有效用户id       EUID
fprintf(STDOUT, "egid=%d\n", posix_getegid());                // 有效组id         EUID
pid=506
ppid=37
pgid=506
sid=37
uid=1000
gid=1000
euid=1000
egid=1000

fork

pcntl_fork

fork

执行过程:

demo4.php

<?php

$pid = pcntl_fork(); // 父进程从这里开始运行

fprintf(STDOUT, "pid=%d run here \n", posix_getpid()); // 子进程从这里开始运行;

  • shell 终端输入 php demo4.php
  • 父进程执行 pcntl_fork 函数;
  • 函数执行成功之后,创建一个子进程,「子进程会复制父进程的代码段和数据段」;
  • 父进程继续执行 fprintf(STDOUT, "pid=%d run here \n", posix_getpid()); 父进程结束;
  • 子进程开始执行 fprintf(STDOUT, "pid=%d run here \n", posix_getpid());,子进程结束。

执行顺序

// fork

fprintf(STDOUT, "我现在的标识是:%d \n", posix_getpid());

$pid = pcntl_fork(); // 父进程从这里开始运行

fprintf(STDOUT, "\$pid=%d \n", $pid); // 子进程从这里开始运行;

if (0 == $pid) {
    // 子进程
    fprintf(STDOUT, "我是子进程我先来,pid=%d, ppid=%d, \$pid=%d run here \n", posix_getpid(), posix_getppid(), $pid);
} else {
    // 父进程
    sleep(2); // 父进程睡眠让子进程先运行

    fprintf(STDOUT, "我是父进程我断后,pid=%d, ppid=%d, \$pid=%d run here \n", posix_getpid(), posix_getppid(), $pid);
}

我现在的标识是:2463 
$pid=2464 
$pid=0 
我是子进程我先来,pid=2464, ppid=2463, $pid=0 run here 
我是父进程我断后,pid=2463, ppid=1381, $pid=2464 run here 

当父进程调用 pcntl_fork 函数之后,创建出子进程,这个时候就有2个进程;

哪个进程先运行是无法确定的,进程调度由系统决定;

通常都是父进程先运行,子进程后运行,如果说父进程先运行,先结束,这个时候子进程就没有父亲,成为了孤儿进程,会被1号进程接管;

变成孤儿进程的后果就是:子进程跑到后台运行,不在前台运行;

所以我们一般让父进程后结束,先让子进程先运行;

当子进程被创建后,它会复制父进程的相关数据「是写时复制 COW copy on write」,父、子进是使用同一块内存空间;

当子进程要修改内存空间时,这个时候,系统会复制新的内存空间给子进程修改;

子进程得到的数据: $pid,它得到的结果是0;

子进程先结束,父进程后结束,这种情况一般来说是正常的,父进程应该回收子进程;

子进程结束时还会生成一些数据,比如说状态码等其它信息,并没有完全释放,需要父进程回收。