原地址:https://www.cnblogs.com/linzhenjie/p/5485436.html
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();
