【注意】最后更新于 October 25, 2022,文中内容可能已过时,请谨慎使用。
3-2进程退出
进程退出
一个程序启动之后,变成了一个进程,在以下情况会退出
- 运行到最后一行语句
- 运行时遇到 return
- 运行时遇到 exit 函数
- 程序异常
- 进程接收到中断信号
一个进程要么是正常,要么是异常结束,无论怎么退出,进程都会返回一个终止状态码,进程结束时不会真的退出,还会驻留在内存中,父进程可以使用 wait 函数来获取进程的终止状态码同时该函数会释放进程的内存空间
######## 僵尸进程
子进程已经结束,父进程还没有使用 wait/wait_pid 来回收(无人收尸)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
$pid = pcntl_fork();
//父进程和子进程都会执行下面代码
if ($pid == -1) {
//错误处理:创建子进程失败时返回-1.
die('could not fork');
} else if ($pid) {
fprintf(STDOUT,"i am father %s\n",posix_getpid());
while(true){
}
// 父进程会得到子进程号,所以这里是父进程执行的逻辑
// pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
} else {
fprintf(STDOUT,"i am child %s\n",posix_getpid());
die('i am child bye');
//子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
}
|
僵尸进程占用的内存空间并未被释放,我们可以到 /proc/pid 目录查看
一个进程运行时,会把进程的信息写入到 /proc/ 目录下,目录名为 pid 号
回收子进程:
PHP 使用 pcntl_wait 函数 https://www.php.net/manual/zh/function.pcntl-wait.php
-
如果没有子进程,可能会返回错误
-
如果子进程还没结束,会阻塞父进程
-
使用参数可以以非阻塞的方式回收
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
// 阻塞方式
$pid = pcntl_fork();
//父进程和子进程都会执行下面代码
if ($pid == -1) {
//错误处理:创建子进程失败时返回-1.
die('could not fork');
} else if ($pid) {
fprintf(STDOUT,"i am father %s\n",posix_getpid());
//父进程会得到子进程号,所以这里是父进程执行的逻辑
$exitPid = pcntl_wait($status); //等待子进程中断,防止子进程成为僵尸进程。
if($exitPid > 0){
fprintf(STDOUT,"子进程 %d 已回收,终止状态码 %d\n",$pid,$status);
}else{
fprintf(STDOUT,"wait error\n");
}
} else {
fprintf(STDOUT,"i am child %s\n",posix_getpid());
while(true){
}
//子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
## 费阻塞方式
$pid = pcntl_fork();
//父进程和子进程都会执行下面代码
if ($pid == -1) {
//错误处理:创建子进程失败时返回-1.
die('could not fork');
} else if ($pid) {
fprintf(STDOUT,"i am father %s\n",posix_getpid());
while (true){
//父进程会得到子进程号,所以这里是父进程执行的逻辑
$exitPid = pcntl_wait($status,WNOHANG); //等待子进程中断,防止子进程成为僵尸进程。
if($exitPid > 0){
fprintf(STDOUT,"子进程 %d 已回收,终止状态码 %d\n",$pid,pcntl_wexitstatus($status));
break;
}
fprintf(STDOUT,"wait ing\n");
}
} else {
fprintf(STDOUT,"i am child %s\n",posix_getpid());
exit(10);
//子进程得到的$pid为0, 所以这里是子进程执行的逻辑。
}
|
######## 使用信号中断程序
如果是程序执行完成,或者使用 return exit 退出,使用 **pcntl_wexitstatus() **函数来获取退出编号,并且可以使用 **pcntl_wifexited() **函数来判断是否完成退出
如果使用中断信号中断程序,那么就要使用pcntl_wifsignaled()函数来判断,或使用pcntl_wifstopped() 函数来获取发送 SIGSTIO SIGTSTP 信号终止的程序退出码
对于不同的中断信号,使用不同的函数进行判断,但是只要退出,**pcntl_wait() **就会返回正常的值