进程标识
一个程序被加载到内存中运行,系统会为这个进程分配相应的标识信息,比如 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
执行过程:
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;
子进程先结束,父进程后结束,这种情况一般来说是正常的,父进程应该回收子进程;
子进程结束时还会生成一些数据,比如说状态码等其它信息,并没有完全释放,需要父进程回收。