php进程通信-进程信号
快一个月没发博文了,之前都在深入研究php多进程tcp服务器,结果到现在也没搞出一个完美的解决方案,所以还是先发下这个月学到的东西吧
注意:本文所有内容均在linux环境下
一:进程信号对照
在php进程信号常量中,有定义以下常量(该表格参考网上的,不完整)
<!--br {mso-data-placement:same-cell; }td {color:#303030; font-size:12.0pt; font-family:宋体; font-weight:400; font-style:normal; text-decoration:none; text-align:general; vertical-align:middle; mso-number-format:General; mso-protection:locked visible; }.et2 {color:#303030; font-size:12.0pt; font-family:宋体; font-weight:400; font-style:normal; text-decoration:none; text-align:general; vertical-align:middle; mso-number-format:General; mso-protection:locked visible; }-->
信号名 |
信号值 |
信号类型 |
信号说明 |
---|---|---|---|
SIGHUP |
1 |
终止进程(终端线路挂断) |
本信号在用户终端连接(正常或非正常、结束时发出, 通常是在终端的控制进程结束时, 通知同一session内的各个作业, 这时它们与控制终端不再关联. |
SIGINT |
2 |
终止进程(中断进程) |
程序终止(interrupt、信号, 在用户键入INTR字符(通常是Ctrl-C、时发出 |
SIGQUIT |
3 |
建立CORE文件终止进程,并且生成CORE文件 |
SIGQUIT 和SIGINT类似, 但由QUIT字符(通常是Ctrl-、来控制. 进程在因收到SIGQUIT退出时会产生core文件, 在这个意义上类似于一个程序错误信 号. |
SIGILL |
4 |
建立CORE文件(非法指令) |
SIGILL 执行了非法指令. 通常是因为可执行文件本身出现错误, 或者试图执行数据段. 堆栈溢出时也有可能产生这个信号. |
SIGTRAP |
5 |
建立CORE文件(跟踪自陷) |
SIGTRAP 由断点指令或其它trap指令产生. 由debugger使用. |
SIGABRT |
6 |
|
SIGABRT 程序自己发现错误并调用abort时产生. |
SIGIOT |
6 |
建立CORE文件(执行I/O自陷) |
SIGIOT 在PDP-11上由iot指令产生, 在其它机器上和SIGABRT一样. |
SIGBUS |
7 |
建立CORE文件(总线错误) |
SIGBUS 非法地址, 包括内存地址对齐(alignment、出错. eg: 访问一个四个字长的整数, 但其地址不是4的倍数. |
SIGFPE |
8 |
建立CORE文件(浮点异常) |
SIGFPE 在发生致命的算术运算错误时发出. 不仅包括浮点运算错误, 还包括溢 出及除数为0等其它所有的算术的错误. |
SIGKILL |
9 |
终止进程(杀死进程) |
SIGKILL 用来立即结束程序的运行. 本信号不能被阻塞, 处理和忽略. |
SIGUSR1 |
10 |
终止进程(用户自定义信号1) |
SIGUSR1 留给用户使用 |
SIGSEGV |
11 |
|
SIGSEGV 试图访问未分配给自己的内存, 或试图往没有写权限的内存地址写数据. |
SIGUSR2 |
12 |
终止进程(用户自定义信号2) |
SIGUSR2 留给用户使用 |
SIGPIPE |
13 |
终止进程(向一个没有读进程的管道写数据) |
Broken pipe |
SIGALRM |
14 |
终止进程(计时器到时) |
SIGALRM 时钟定时信号, 计算的是实际的时间或时钟时间. alarm函数使用该信号. |
SIGTERM |
15 |
终止进程(软件终止信号) |
SIGTERM 程序结束(terminate、信号, 与SIGKILL不同的是该信号可以被阻塞和处理. 通常用来要求程序自己正常退出. shell命令kill缺省产生这个信号. |
SIGCHLD |
17 |
忽略信号(当子进程停止或退出时通知父进程) |
SIGCHLD 子进程结束时, 父进程会收到这个信号. |
SIGCONT |
18 |
忽略信号(继续执行一个停止的进程) |
SIGCONT 让一个停止(stopped、的进程继续执行. 本信号不能被阻塞. 可以用一个handler来让程序在由stopped状态变为继续执行时完成特定的工作. 例如, 重新显示提示符 |
SIGSTOP |
19 |
停止进程(非终端信号) |
SIGSTOP 停止(stopped、进程的执行. 注意它和terminate以及interrupt的区别: 该进程还未结束, 只是暂停执行. 本信号不能被阻塞, 处理或忽略. |
SIGTSTP |
20 |
停止进程(终端信号) |
SIGTSTP 停止进程的运行, 但该信号可以被处理和忽略. 用户键入SUSP字符时 (通常是Ctrl-Z、发出这个信号 |
SIGTTIN |
21 |
停止进程(后端进程读终端) |
SIGTTIN 当后台作业要从用户终端读数据时, 该作业中的所有进程会收到SIGTTIN 信号. 缺省时这些进程会停止执行. |
SIGTTOU |
22 |
停止进程(后端进程写终端) |
SIGTTOU 类似于SIGTTIN, 但在写终端(或修改终端模式、时收到. |
SIGURG |
23 |
忽略信号(I/O紧急信号) |
SIGURG 有”紧急”数据或out-of-band数据到达socket时产生. |
SIGXCPU |
24 |
终止进程(CPU实现超时) |
SIGXCPU 超过CPU时间资源限制. 这个限制可以由getrlimit/setrlimit来读取/ 改变 |
SIGXFSZ |
25 |
终止进程(文件长度过长) |
SIGXFSZ 超过文件大小资源限制. |
SIGVTALRM |
26 |
终止进程(虚拟计时器到时) |
SIGVTALRM 虚拟时钟信号. 类似于SIGALRM, 但是计算的是该进程占用的CPU时间. |
SIGPROF |
27 |
终止进程(统计分布图用计时器到时) |
SIGPROF 类似于SIGALRM/SIGVTALRM, 但包括该进程用的CPU时间以及系统调用的 时间. |
SIGWINCH |
28 |
忽略信号(窗口大小发生变化) |
SIGWINCH 窗口大小改变时发出. |
SIGIO |
29 |
忽略信号(描述符上可以进行I/O) |
SIGIO 文件描述符准备就绪, 可以开始进行输入/输出操作. |
SIGPWR |
30 |
|
SIGPWR Power failure |
二:php基础进程相关函数
注意:(需要pcntl扩展支持)
具体相关函数可查看php手册:http://php.net/manual/zh/book.pcntl.php
1:declare(ticks=1);每执行一条php低级语句,则触发一次register_tick_function函数,并且每执行1条低级语句会检查一次该进程是否有未处理过的信号.,该函数是在php版本小于5.3,用于php进行php信号处理的函数,例如:
<?php
declare(ticks=1);//每执行一条时,触发register_tick_function()注册的函数
$a=1;//再注册之前,不记录
$a=1;//再注册之前,不记录
function test(){//定义一个函数
echo "执行\n";
}
register_tick_function('test');//该条注册函数会被当成低级语句被执行
for($i=0;$i<=3;$i++){//for算一条低级语句
$i=$i;//赋值算一条
}
复制
在php7.2中,运行结果如下:
2:pcntl_signal;注册一个信号处理函数,和declare(ticks=1)组合使用:
declare(ticks = 1);
pcntl_signal(SIGINT,function(){
echo "触发信号Ctrl+c";
});
while(1){
sleep(1);//死循环运行低级语句
}
复制
当执行该脚本,再ctrl+c的时候,将会捕捉到该信号,并输出,如图:
3:getmypid.获取当前进程id,posix_kill发送信号
为什么会拿这2个一起说呢?因为posix_kill函数如果需要发送信号,是需要进程id的,而getmypid(),则是获取当前进程id的函数,
以下是将上面的函数组合使用的例子:
<?php
//文件一
declare(ticks = 1);
echo getmypid();//获取当前进程id
pcntl_signal(SIGUSR1,function(){
echo "触发信号用户自定义信号1";
});
while(1){
sleep(1);//死循环运行低级语句
}
复制
<?php
//文件二
posix_kill(文件一进程, SIGUSR1);
复制
运行文件1结果:
运行文件2之后文件1结果:
4:到这之后,你可能会想到,declare每次运行一次低级语句,都会尝试执行2种结果,效率会不会很差呢?答案是会的,所以在php5.3之后,有了新的函数,那就是pcntl_signal_dispatch
pcntl_signal_dispatch: 调用等待信号的处理器,有了它,将不在需要declare,只需要在循环中增加该函数,就可以调用信号通过了:
<?php
echo getmypid();//获取当前进程id
pcntl_signal(SIGUSR1,function(){
echo "触发信号用户自定义信号1";
});
while(1){
pcntl_signal_dispatch();
sleep(1);//死循环运行低级语句
}
复制
结果和3同样
5:看到4,你可能会觉得,信号处理还是没有那么的智能,能不能不做死循环,就完成异步的信号接收并处理呢?在php7.1之后,有了新的信号处理函数:pcntl_async_signals,返回或设置是否异步信号处理:
<?php
//文件一
echo getmypid();
pcntl_async_signals(true);//设置异步信号
pcntl_signal(SIGUSR1,function(){//安装个user1信号处理函数
echo "触发信号";
posix_kill(getmypid(),SIGSTOP);
});
posix_kill(getmypid(),SIGSTOP);//给进程发送暂停信号
复制
<?php
//文件2
posix_kill(文件1进程, SIGCONT);//给进程发送继续信号
posix_kill(文件1进程, SIGUSR1);//给进程发送user1信号
复制
首先文件1运行,再给文件2运行之后,文件1的结果图:
文件1进程strace 命令截图:
可看到,进程休眠之后,被9271进程(文件2)唤醒之后并发送了siguse1信号,再然后输出了一段文字,再然后自己给自己发送了进程休眠信号,继续休眠
linux 查看进程命令.可看:
https://blog.csdn.net/liangzhao_jay/article/details/50457197
6:pcntl_alarm和创建一个计时器,在指定的秒数后向进程发送一个SIGALRM信号。每次对 pcntl_alarm()的调用都会取消之前设置的alarm信号。例如:
<?php
pcntl_signal(SIGALRM, function () {
echo '定时到时' . PHP_EOL;
});
pcntl_alarm(5);
$i=0;
while(1){
echo $i.PHP_EOL;$i++;
pcntl_signal_dispatch();
sleep(1);
}
复制
该函数使用场景之一:php熔断
<?php
pcntl_async_signals(true);
pcntl_signal(SIGALRM, function () {
echo 'php处理超时' . PHP_EOL;
});
pcntl_alarm(30);
/*
* 这里是一大段php处理函数
* */
pcntl_alarm(-1);
复制
先进行30秒的定时,当处理函数超过30秒时,将触发php处理超时函数,从而进行超时逻辑,当在30秒处理完毕时,php将关闭改定时信号,正常往下执行
三:其他
1:php进程信号中,无法捕获SIGKILL信号,该信号将会强制关闭进程
华为开发者空间发布
让每位开发者拥有一台云主机
- 点赞
- 收藏
- 关注作者
评论(0)