PHP進程通信基礎——信號
使用信號通信。可以使用
kill -l
來查看當前系統的信號類型。
每個信號所代表的的詳細含義,請查看我的這篇博客:http://www.cnblogs.com/roverliang/p/6050964.html
使用信號的時候可以通過php --version
來查看當前PHP的版本。已決定使用哪種方式來進行進程間的信號通信。
[root@roverliang ipc]# php --version
PHP 5.6.24 (cli) (built: Aug 15 2016 19:14:02)
Copyright (c) 1997-2016 The PHP Group
Zend Engine v2.6.0, Copyright (c) 1998-2016 Zend Technologies
使用pcntl_signal_dispatch
函數 需要PHP 版本(PHP 5 >= 5.3.0, PHP 7)
如果PHP版本小於5.3.一些大公司可能會低於這個版本。這個時候會使用 declare(ticks=1)
,意思為每執行一條低級指令,
就會去檢測是否出現該信號。詳細的介紹可以查看官網的介紹:http://php.net/manual/zh/control-structures.declare.php
官網解釋如下:Tick(時鍾周期)是一個在 declare 代碼段中解釋器每執行 N 條可計時的低級語句就會發生的事件。N 的值是在 declare 中的 directive 部分用 ticks=N 來指定的。
那么什么是低級語句呢:如下代碼所示:
for ($i = 0; $i < 3; $i++) {
echo $i.PHP_EOL;
}
那么這個for 循環中就含有三條低級指令。每輸出一條$i。就會去檢測下是否發生了已注冊的事件,可想而知,這樣效率是比較低的。所以如果檢測到自己的PHP大於等於5.3 。就使用pcntl_singal_dispath 來進行信號派送。
主進程在啟動的時候注冊一些信號處理函數。
/**
* @param $signal 信號
*/
function signalHandal($signal)
{
switch ($signal) {
case SIGINT:
//do something
break;
case SIGHUP:
//do something
break;
default :
//do something
break;
}
}
然后將信號處理器與信號處理函數綁定:
//根據不同的信號,安裝不同的信號處理器
pcntl_signal(SIGINT, 'signalHandal');
pcntl_signal(SIGHUP, 'signalHandal');
pcntl_signal(SIGUSR1, 'signalHandla');
在子進程監聽信號,如果出現該信號,就調用預安裝的信號處理函數
//分配信號。
pcntl_signal_dispatch($signal);
我們來整理下思路:
1、定義信號發生所需要處理事件的函數
2、將信號和信號處理函數綁定,稱為信號安裝。
3、信號監聽或者分發,出現信號調用已安裝的信號。
理解好上面的信號概念,我們來看一個demo:
<?php
$parentpid = posix_getpid();
echo "parent progress pid:{$parentpid}\n";
//定義一個信號處理函數
function sighandler($signal) {
if ($signal == SIGINT) {
$pid = getmypid();
exit("{$pid} process, Killed!".PHP_EOL);
}
}
//php version < 5.3 .每執行一條低級指令,就檢查一次是否出現該信號。效率損耗很大。
//declare(ticks=1);
$child_list = [];
//注冊一個信號處理器。當發出該信號的時候對調用已定義的函數
pcntl_signal(SIGINT, 'sighandler');
for($i = 0; $i < 3; $i++) {
$pid = pcntl_fork();
if ($pid == 0) {
//子進程
while (true) {
//調用已安裝的信號信號處理器,為了檢測是否有新的信號等待dispatching
pcntl_signal_dispatch();
echo "I am child: ".getmypid(). " and i am running !".PHP_EOL;
sleep(rand(1,3));
}
} elseif($pid > 0) {
$child_list[] = $pid;
} else {
die('fork fail!'.PHP_EOL);
}
}
sleep(5);
foreach ($child_list as $key => $pid) {
posix_kill($pid, SIGINT);
}
sleep(2);
echo "{$parentpid} parent is end".PHP_EOL;