我们事情中打仗最多的便是 进程,但是我们对它又比较陌生,由于它是业务不须要关心的地方,既有的公有组件和操作系统已经对我们屏蔽了它的繁芜性。然后跟它的打仗韶光一长,我们难免会对它产生好奇:How it works?
什么是进程
进程是 程序的实体,是系统进行 资源分配和调度的基本单位,是操作系统构造的根本。每个进程都有自己唯一标识(PID),每个进程都有父进程,这些父进程也有父进程,所有进程都是init进程(PID 为 1)的子进程。
我们来直不雅观感想熏染下它的存在,可以说它是看不见又摸不着。

$ pstree -pinit(1)-+-init(3)---bash(4) |-nginx(771)-+-nginx(773) | |-nginx(774) | |-nginx(776) | `-nginx(777) |-php-fpm(702)-+-php-fpm(707) `-php-fpm(712)
进程分类前台进程
前台进程具有掌握终端,会堵塞掌握终端。它的特点是:
可以同用户交互,但随意马虎被意外终止;有较高的相应速率,优先级别稍高;$ php server.php startPHPServer start [OK] # 堵塞了/_ \
常日,在掌握终端利用Ctrl+C组合键,会导致前台进程终止退出。
守护进程守护进程是一种运行在后台的分外进程,由于它不属于任何一个终端,以是不会收到任何终端发来的任何旗子暗记。它与前台进程显著的差异是:
它没有掌握终端,不能直接和用户交互,在后台运行;它不受用户登录和注销的影响,只受开机或关机的影响,可以长期运行;常日我们编写的程序,都须要在 后台不终止的长期运行 ,此时就可以利用守护进程。当然,我们可以在代码中调用系统函数,或者直接在启动命令后追加&操作符,如下:
$ nohup php server.php start &使进程分开掌握终端运行
常日&与 nohup 结合利用,忽略 SIGHUP 旗子暗记来实现一个守护进程。该办法对业务代码侵入最小,方便且本钱低,常用于临时实行任务脚本的场景。
进程间通信(InterProcess Communication)进程的用户空间是相互独立的,一样平常而言是不能相互访问。但很多情形下,进程间须要相互通信来进行数据传输、共享数据、关照事宜、进程掌握等,这就必须通过内核实现进程间通信。
进程间通信有管道、行列步队、旗子暗记、共享内存、套接字等办法,本文只先容后 3 种。
共享内存(Shared Memory)共享内存是一段被映射到多个进程地址空间的内存,虽然这段共享内存是由一个进程创建,但是多个进程都可以访问。如下图:
共享内存是最快的进程间通信办法,但是可能会存在竞争,因此须要加锁。Linux 支持三种共享内存:mmap、Posix、以及 System V。
套接字(Socket)套接字是一个通信链的句柄,可以用域、端口号、协议类型来表示一个套接字,个中域分为 Internet 网络(IP 地址)和 UNIX 文件(Sock 文件)两种。当域为 Internet 网络时,通信流程如下图:
特殊的是,当套接字域为 Internet 网络时,可以实现 跨主机的进程间通信。因此,若要实现跨主机进行进程间通信,则须选用套接字。
旗子暗记(Signal)旗子暗记受事宜驱动,是一种异步且最繁芜的通信办法,用于关照接管进程有某个事宜已经发生,因此常用于事宜处理。旗子暗记的处理机制,如下图:
常用的旗子暗记值
在 Linux 系统中,可利用kill -l命令查看这 62 个旗子暗记值。个中常用值如下:
旗子暗记名称
值
解释
进程默认行为
SIGHUP
1
终端掌握进程结束
Terminate
SIGINT
2
键盘Ctrl+C被按下
Terminate
SIGQUIT
3
键盘Ctrl+/被按下
Dump
SIGKILL
9
无条件结束进程
Terminate
SIGUSR1
10
用户保留
Terminate
SIGUSR2
12
用户保留
Terminate
SIGALRM
14
时钟定时旗子暗记
Terminate
SIGTERM
15
程序结束
Terminate
SIGCHLD
16
子进程结束
Ignore
产生旗子暗记的办法实际中,硬件或者软件中断都会触发旗子暗记,但这里只列举两种旗子暗记产生办法。
终端按键按键/命令
旗子暗记名称
Ctrl+C
SIGINT
Ctrl+\
SIGQUIT
EXIT
SIGHUP
系统调用通过kill系统调用发送旗子暗记。例如,在 Shell 中利用kill -9发送 SIGKILL 旗子暗记。对付kill调用,须要把稳以下两种分外情形:
1、 分外旗子暗记
可以发送编号为0的旗子暗记来 检测进程是否存活。
$pid = 577;if (posix_kill($pid, 0)) { echo "进程存在\n";} else { echo "进程不存在\n";}
2、 分外 PID
这里的参数$pid,根据取值范围不同,含义也不同。详细如下:
$pid > 0: 向 PID 为 $pid 的进程发送旗子暗记$pid = 0:向当提高程组所有进程发送旗子暗记,比较常用;$pid = -1:向所有进程(除 PID 为 1)发送旗子暗记(权限);进程的处理办法进程共有 3 种处理旗子暗记的办法:
默认行为;忽略;捕获并处理—注册旗子暗记处理器后,当捕获到旗子暗记时,实行对应的处理器;个中,默认行为进一步可以细分为以下几种:
默认处理类型
描述
Terminate
进程被中止(杀去世)
Dump
进程被中止(杀去世),并且输出 dump 文件
Ignore
旗子暗记被忽略
Stop
进程被停滞
旗子暗记的默认行为类型,见 常用的旗子暗记值 默认行为部分。
进程间关系利用ps -ajx命令查看所有进程信息,如下:
#父PID PID 组ID 会话ID 终端 韶光 名称PPID PID PGID SID TTY TIME COMMAND 0 1 1 1 ? 0:00 /init ro 1 43 43 43 ? 0:00 /usr/sbin/sshd 43 11134 11134 11134 ? 0:00 sshd: root@pts/111134 11169 11169 11169 pts/1 0:00 -bash11169 11251 11251 11169 pts/1 0:00 PHPServer: master 11251 11252 11251 11169 pts/1 0:36 PHPServer: worker 11251 11253 11251 11169 pts/1 0:42 PHPServer: worker
进程组(Process Group)
进程组是一个或多个进程的凑集。每个进程除了有一个 PID 之外还有一个进程组 ID(GID),每个进程都属于一个进程组,每个进程都有一个组长进程。
如上图中,1 个PHPServer: master主进程和 2 个PHPServer: worker子进程,属于同一个进程组11251,可以看出主进程是组长进程。
会话(Session)会话是一个或多个进程组的凑集,一个会话有对应的掌握终端。如上图中,4 个PHPServer进程和-bash进程同属于一个会话,由于他们在一个pts/1的掌握终端。
须要解释的是,当用户退出(Logout)会话往后,系统默认对该会话下的进程进行如下操作:
系统向该会话发出 SIGHUP 旗子暗记;该会话将 SIGHUP 旗子暗记发给所有子进程;子进程收到 SIGHUP 旗子暗记后,自动退出;而对付后台进程,用户在退出时系统默认不会发送 SIGHUP 旗子暗记,这是由 Shell 的huponexit参数(默认off)掌握。可通过shopt -s huponexit设置成on(当前会话有效),此时后台进程会收到 SIGHUP 旗子暗记。
进程模型从进程层面来说,程序可以分为单进程和多进程模型。
单进程单进程模型的程序,只有一个进程在运行。他是最基本的进程模型,实现起来比较大略,Redis 便是采取这种进程模型。
多进程为了提高程序的并发处理能力,程序由单进程逐步演化成了多进程,一 个 Master 进程和多个 Worker 进程是多进程常见的构成形态。可以说,现在大部分程序都是多进程模型,个中 Nginx 是范例的代表。
总结到这里,我们已经对进程有了根本的认识,后续我将用 PHP 一步步实现一个 PHPServer 运用。