PHP系統編程--03.PHP進程信號處理


PHP的pcntl擴展提供了信號處理的功能,利用它可以讓PHP來接管信號的處理,在開發服務器端守護進程方面,信號處理至關重要。

函數原型

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

第一個參數是信號ID
第二個參數是信號發生時回調的PHP函數。
第三個參數是是否restart,是否重新注冊此信號。這個參數如果為false,那此信號只注冊處理一次。

pcntl_signal的實現

<?php
//信號處理需要注冊ticks才能生效,這里務必注意
//PHP5.4以上版本就不再依賴ticks了
declare(ticks = 1);

function sig_handler($signo){
    switch ($signo) {
        case SIGUSR1: echo "SIGUSR1\n"; break;
        case SIGUSR2: echo "SIGUSR2\n"; break;
        default:      echo "unknow";    break;
    }
}

//安裝信號觸發器器
pcntl_signal(SIGUSR1, "sig_handler");
pcntl_signal(SIGUSR2, "sig_handler");

//向當前進程發送SIGUSR1信號
posix_kill(posix_getpid(), SIGUSR1);
posix_kill(posix_getpid(), SIGUSR2);

?>

執行此代碼會在終端輸出你想要的結果,其實官方的pcntl_signal性能極差,主要是PHP的函數無法直接注冊到操作系統信號設置中,所以pcntl信號需要依賴tick機制來完成。
pcntl_signal的實現原理是,觸發信號后先將信號加入一個隊列中。然后在PHP的ticks回調函數中不斷檢查是否有信號,如果有信號就執行PHP中指定的回調函數,如果沒有則跳出函數。
ticks=1表示每執行1行PHP代碼就回調此函數。實際上大部分時間都沒有信號產生,但ticks的函數一直會執行。
比較好的做法是去掉ticks,轉而使用pcntl_signal_dispatch,在代碼循環中自行處理信號。

pcntl_signal_dispatch的實現

<?php
// 定義一個處理器,接收到SIGINT信號后只輸出一行信息
function signalHandler($signo) {
    switch ($signo) {
        case SIGUSR1: echo "SIGUSR1\n"; break;
        case SIGUSR2: echo "SIGUSR2\n"; break;
        default:      echo "unknow";    break;
    }
}

//安裝信號觸發器器
pcntl_signal(SIGINT, 'signalHandler');
while (true) {
    sleep(1);
    posix_kill(posix_getpid(), SIGUSR1);
    pcntl_signal_dispatch(); //接收到信號時,調用注冊的signalHandler()
}

實戰:用信號來處理函數超時

<?php
function a(){
    sleep(10);
    echo "OK\n";
}
function b(){
    echo "Stop\n";
}
function c(){
    usleep(100000);
}
//信號處理代碼
function sig(){
    throw new Exception;
}
try{
    pcntl_alarm(2); //設定超時后觸發的信號
    pcntl_signal(SIGALRM, "sig");
    pcntl_signal_dispatch();
    a();
    pcntl_alarm(0);
}catch(Exception $e){
    echo "timeout\n";
}

b();
a(); //等待十秒后完成
b();





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM