中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

PHP進程信號如何處理

發布時間:2023-04-14 10:51:54 來源:億速云 閱讀:98 作者:iii 欄目:編程語言

這篇文章主要介紹“PHP進程信號如何處理”的相關知識,小編通過實際案例向大家展示操作過程,操作方法簡單快捷,實用性強,希望這篇“PHP進程信號如何處理”文章能幫助大家解決問題。

一、在Linux操作系統中有哪些信號

1、簡單介紹信號

信號是事件發生時對進程的通知機制,有時又稱為軟件中斷。一個進程可以向另一個進程發送信號,比如子進程結束時都會向父進程發送一個SIGCHLD(17號信號)來通知父進程,所以有時信號也被當作一種進程間通信的機制。

在linux系統下,通常我們使用 kill -9 XXPID來結束一個進程,其實這個命令的實質就是向某進程發送SIGKILL(9號信號),對于在前臺進程我們通常用Ctrl+c快捷鍵來結束運行,該快捷鍵的實質是向當前進程發送SIGINT(2號信號),而進程收到該信號的默認行為是結束運行

2、常用信號

下邊這些信號,可以使用kill -l命令進行查看PHP進程信號如何處理

下邊介紹幾個比較重要且常用的信號:

信號名信號值信號類型信號描述
SIGHUP1終止進程(終端線路掛斷)本信號在用戶終端連接(正常或非正常、結束時發出, 通常是在終端的控制進程結束時, 通知同一session內的各個作業, 這時它們與控制終端不再關聯
SIGQUIT2終止進程(中斷進程)程序終止(interrupt、信號, 在用戶鍵入INTR字符(通常是Ctrl-C、時發出
SIGQUIT3建立CORE文件終止進程,并且生成CORE文件進程,并且生成CORE文件 SIGQUIT 和SIGINT類似, 但由QUIT字符(通常是Ctrl-、來控制. 進程在因收到SIGQUIT退出時會產生core文件, 在這個意義上類似于一個程序錯誤信 號
SIGFPE8建立CORE文件(浮點異常)SIGFPE 在發生致命的算術運算錯誤時發出. 不僅包括浮點運算錯誤, 還包括溢 出及除數為0等其它所有的算術的錯誤
SIGKILL9終止進程(殺死進程)SIGKILL 用來立即結束程序的運行. 本信號不能被阻塞, 處理和忽略
SIGSEGV11
SIGSEGV 試圖訪問未分配給自己的內存, 或試圖往沒有寫權限的內存地址寫數據
SIGALRM14終止進程(計時器到時)SIGALRM 時鐘定時信號, 計算的是實際的時間或時鐘時間. alarm函數使用該信號
SIGTERM15終止進程(軟件終止信號)SIGTERM 程序結束(terminate、信號, 與SIGKILL不同的是該信號可以被阻塞和處理. 通常用來要求程序自己正常退出. shell命令kill缺省產生這個信號
SIGCHLD17忽略信號(當子進程停止或退出時通知父進程)SIGCHLD 子進程結束時, 父進程會收到這個信號
SIGVTALRM26終止進程(虛擬計時器到時)SIGVTALRM 虛擬時鐘信號. 類似于SIGALRM, 但是計算的是該進程占用的CPU時間
SIGIO29忽略信號(描述符上可以進行I/O)SIGIO 文件描述符準備就緒, 可以開始進行輸入/輸出操作

二、PHP中處理信號相關函數

PHP的pcntl擴展以及posix擴展為我們提供了若干操作信號的方法(若想使用這些函數,需要先安裝這幾個擴展)

下邊具體介紹幾個我在本次任務中用到的方法:

declare

declare結構用來設定一段代碼的執行指令。declare的語法和其它流程控制結構相似

declare (directive)
   statement

directive部分允許設定declare代碼段的行為。目前只認識兩個指令:ticks和encoding。declare代碼段中的 statement部分將被執行——怎樣執行以及執行中有什么副作用出現取決于directive中設定的指令

Ticks

Tick(時鐘周期)是一個在declare代碼段中解釋器每執行N條可計時的低級語句就會發生的事件N的值是在declare 中的directive部分用ticks=N來指定的。不是所有語句都可計時。通常條件表達式參數表達式都不可計時。在每個tick中出現的事件是由register_tick_function()來指定的,注意每個 tick 中可以出現多個事件 更詳細的內容。

<?php
declare(ticks=1);//每執行一條時,觸發register_tick_function()注冊的函數
$a=1;//在注冊之前,不算
function test(){//定義一個函數
   echo "執行\n";
}
register_tick_function('test');//該條注冊函數會被當成低級語句被執行
for($i=0;$i<=2;$i++){//for算一條低級語句
   $i=$i;//賦值算一條
}
輸出:六個“執行”
pcntl_signal

pcntl_signal,安裝一個信號處理器

pcntl_signal ( int $signo , callback $handler [, bool $restart_syscalls = true ] ) : bool

函數pcntl_signal()為signo指定的信號安裝一個新的信號處理器

declare(ticks = 1);
pcntl_signal(SIGINT,function(){
   echo "你按了Ctrl+C".PHP_EOL;
});
while(1){
   sleep(1);//死循環運行低級語句
}
輸出:當按Ctrl+C之后,會輸出“你按了Ctrl+C”
posix_kill

posix_kill,向進程發送一個信號

posix_kill ( int $pid , int $sig ) : bool

第一個參數為進程ID,第二個參數為你要發送的信號

a.php
<?php
declare(ticks = 1);
echo getmypid();//獲取當前進程id
pcntl_signal(SIGINT,function(){
   echo "你給我發了SIGINT信號";
});
while(1){
   sleep(1);
}

b.php
<?php
posix_kill(執行1.php時輸出的進程id, SIGINT);
pcntl_signal_dispatch

pcntl_signal_dispatch,調用等待信號的處理器

pcntl_signal_dispatch ( void ) : bool

函數pcntl_signal_dispatch()調用每個等待信號通過pcntl_signal()安裝的處理器

<?php
echo "安裝信號處理器...\n";
pcntl_signal(SIGHUP,  function($signo) {
    echo "信號處理器被調用\n";
});
echo "為自己生成SIGHUP信號...\n";
posix_kill(posix_getpid(), SIGHUP);
echo "分發...\n";
pcntl_signal_dispatch();
echo "完成\n";
?>

輸出:
安裝信號處理器...
為自己生成SIGHUP信號...
分發...
信號處理器被調用
完成
pcntl_async_signals()

異步信號處理,用于啟用無需 ticks (這會帶來很多額外的開銷)的異步信號處理。(PHP>=7.1)

<?php
pcntl_async_signals(true); // turn on async signals

pcntl_signal(SIGHUP,  function($sig) {
   echo "SIGHUP\n";
});

posix_kill(posix_getpid(), SIGHUP);

輸出:
SIGHUP

三、PHP中處理信號量的方式

前邊我們知道我們可以通過declare(ticks=1)和pcntl_signal組合的方式監聽信號,即每一條PHP低級語句,就會檢查一次當前進程是否有未處理的信號,這其實是十分耗性能的。

pcntl_signal的實現原理是,觸發信號后先將信號加入一個隊列中。然后在PHP的ticks回調函數中不斷檢查是否有信號,如果有信號就執行PHP中指定的回調函數,如果沒有則跳出函數。

PHP_MINIT_FUNCTION(pcntl)
{
php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
php_add_tick_function(pcntl_signal_dispatch TSRMLS_CC);

return SUCCESS;
}

在PHP5.3之后,有了pcntl_signal_dispatch函數。這個時候將不在需要declare,只需要在循環中增加該函數,就可以調用信號通過了:

<?php
echo getmypid();//獲取當前進程id
pcntl_signal(SIGUSR1,function(){
   echo "觸發信號用戶自定義信號1";
});
while(1){
   pcntl_signal_dispatch();
   sleep(1);//死循環運行低級語句
}

大家都知道PHP的ticks=1表示每執行1行PHP代碼就回調此函數。實際上大部分時間都沒有信號產生,但ticks的函數一直會執行。如果一個服務器程序1秒中接收1000次請求,平均每個請求要執行1000行PHP代碼。那么PHP的pcntl_signal,就帶來了額外的 1000 * 1000,也就是100萬次空的函數調用。這樣會浪費大量的CPU資源。比較好的做法是去掉ticks,轉而使用pcntl_signal_dispatch,在代碼循環中自行處理信號。 pcntl_signal_dispatch 函數的實現:

void pcntl_signal_dispatch()
{
//.... 這里略去一部分代碼,queue即是信號隊列
while (queue) {
 if ((handle = zend_hash_index_find(&PCNTL_G(php_signal_table), queue->signo)) != NULL) {
  ZVAL_NULL(&retval);
  ZVAL_LONG(&param, queue->signo);

  /* Call php signal handler - Note that we do not report errors, and we ignore the return value */
  /* FIXME: this is probably broken when multiple signals are handled in this while loop (retval) */
  call_user_function(EG(function_table), NULL, handle, &retval, 1, &param TSRMLS_CC);
  zval_ptr_dtor(&param);
  zval_ptr_dtor(&retval);
 }
 next = queue->next;
 queue->next = PCNTL_G(spares);
 PCNTL_G(spares) = queue;
 queue = next;
}
}

但是上邊這種,也有個惡心的地方就是,它得放在死循環中。PHP7.1之后出來了一個完成異步的信號接收并處理的函數: pcntl_async_signals

<?php
//a.php
echo getmypid();
pcntl_async_signals(true);//開啟異步監聽信號
pcntl_signal(SIGUSR1,function(){
   echo "觸發信號";
   posix_kill(getmypid(),SIGSTOP);
});
posix_kill(getmypid(),SIGSTOP);//給進程發送暫停信號

//b.php
posix_kill(文件1進程, SIGCONT);//給進程發送繼續信號
posix_kill(文件1進程, SIGUSR1);//給進程發送user1信號

通過pcntl_async_signals方法,就不用再寫死循環了。

監聽信號的包:

https://github.com/Rain-Life/monitorSignal

關于“PHP進程信號如何處理”的內容就介紹到這里了,感謝大家的閱讀。如果想了解更多行業相關的知識,可以關注億速云行業資訊頻道,小編每天都會為大家更新不同的知識點。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

php
AI

卢湾区| 凉城县| 两当县| 泰州市| 桐乡市| 海门市| 庄河市| 关岭| 许昌县| 福鼎市| 望奎县| 黄大仙区| 汉寿县| 高清| 阳朔县| 旬阳县| 汶上县| 崇左市| 阿瓦提县| 南昌县| 肇庆市| 南涧| 离岛区| 准格尔旗| 上杭县| 喀喇沁旗| 依安县| 杭锦后旗| 嵊州市| 莫力| 永平县| 株洲市| 平舆县| 始兴县| 五河县| 牡丹江市| 尉犁县| 唐河县| 余江县| 苗栗市| 东明县|