惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

博客园 - 【当耐特】
Stack Overflow Blog
Stack Overflow Blog
V
Visual Studio Blog
小众软件
小众软件
The Cloudflare Blog
T
Tailwind CSS Blog
Apple Machine Learning Research
Apple Machine Learning Research
爱范儿
爱范儿
美团技术团队
WordPress大学
WordPress大学
罗磊的独立博客
Microsoft Azure Blog
Microsoft Azure Blog
A
About on SuperTechFans
Last Week in AI
Last Week in AI
月光博客
月光博客
博客园 - Franky
奇客Solidot–传递最新科技情报
奇客Solidot–传递最新科技情报
G
Google Developers Blog
GbyAI
GbyAI
B
Blog
大猫的无限游戏
大猫的无限游戏
博客园 - 聂微东
Hugging Face - Blog
Hugging Face - Blog
博客园 - 叶小钗

WangDeer

非机动车交通规则测验 微软 50 周年壁纸是在 macOS上设计的? 「转」西二旗折叠:蜂巢经济学启示录 难得空明 Ubuntu Clean ApidocJs apigroup Support Chinese int(10)里面的10是什么意思? 5-3 会话 2021-03-25 「PHP架构师」面试准备 Laravel 上传 Docx 文件,表单验证不通过 4-4 发送信号 4-3 信号集 4-2 编写中断信号处理程序 2022-03-10 面试复盘 4-1 什么是中断信号(软中断) 3-7 进程查看 3-6 SUID特权进程 3-5多进程编写 3-4进程调度 3-3进程exec 3-2进程退出和回收 2-3解释器文件 2-2命令行参数与环境参数表 2-1程序与进程 1-1课程介绍 终极复盘 第八章 传承篇 第七章 自由篇 第六章 品牌篇 第五章 作品篇
3-1进程标识与fork
王二 · 2022-02-28 · via WangDeer

进程标识

一个程序被加载到内存中运行,系统会为这个进程分配相应的标识信息,比如 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

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;

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

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