php進程間通信的另外一個手段就是通過信號來在進程間傳遞信息。信號是一種系統調用,通常我們用的kill命令就是發送某個信號給某個進程的。
在開發服務器端守護進程方面,信號處理至關重要。PHP的pcntl擴展提供了信號處理的功能,利用它可以讓PHP來接管信號的處理。
今天,我們就來給大家講一講PHP中的信號處理。
什么是信號?
信號是事件發生時對進程的通知機制,有時又稱為軟件中斷。一個進程可以向另一個進程發送信號,比如子進程結束時都會向父進程發送一個SIGCHLD(17號信號)來通知父進程,所以有時信號也被當作一種進程間通信的機制。
信號的產生是有多種方式的,下面是常見的幾種:
●鍵盤上按某些組合鍵,比如Ctrl+C或者Ctrl+D等,會產生SIGINT信號。
●使用posix kill調用,可以向某個進程發送指定的信號。
●遠程ssh終端情況下,如果你在服務器上執行了一個阻塞的腳本,正在阻塞過程中你關閉了終端,可能就會產生SIGHUP信號。
●硬件也會產生信號,比如OOM了或者遇到除0這種情況,硬件也會向進程發送特定信號。
而進程在收到信號后,可以有如下三種響應:
●直接忽略,不做任何反映。就是俗稱的完全不鳥。但是有兩種信號,永遠不會被忽略,一個是SIGSTOP,另一個是SIGKILL,因為這兩個進程提供了向內核最后的可靠的結束進程的辦法。
●捕捉信號并作出相應的一些反應,具體響應什么可以由用戶自己通過程序自定義。
●系統默認響應。大多數進程在遇到信號后,如果用戶也沒有自定義響應,那么就會采取系統默認響應,大多數的系統默認響應就是終止進程。
PHP信號處理案例
我們在FPM模式下寫代碼,不會遇到信號處理相關的問題,但是CLI模式下一些常駐內存的腳本,如何能夠自由的重啟、關閉、退出前做一些清理工作(斷開鏈接,刪除臨時文件等)?
pcntl_signal是PHP的信號處理注冊方法,這個是pcntl初始化的時候,將pcntl_signal_dispatch注冊為tick的處理函數。
pcntl_signal會將處理函數放到信號集合中(PHP的hash table),而php_signale4最終會調用sigaction進行底層的信號管理。
這里我省略了大量代碼,將關鍵的點標記了出來,其實PHP維護一個自己的信號集合,每當調用 pcntl_signal_dispatch時就會查詢是否有信號,上面的SIG_BLOCK會將信號阻塞,這樣只有我們把關鍵的代碼執行完畢之后,再去觸發信號處理函數以保證數據和程序邏輯的完整性。
PHP如何優雅的處理信號
經常見到身邊的程序員們,每當需要重啟PHP-FPM進程的時候,使用的招數是kill掉所有PHP進程,然后新啟動。一般情況沒啥問題,但有些時候可能某個進程的任務還沒執行完,直接把人家中斷了略顯粗暴。
其實只要你給PHP的Master進程發送一條USR2信號,它便會再處理完所有任務后,重啟子進程,這才是所謂的優雅~
以上圖為例,如果我們想讓進程優雅退出的時候,只需要發送SIGTERM信號即可。需要注意的是SIGKILL和SIGSTOP信號會略過信號阻塞會將進程直接停止,還有就是信號會中斷睡眠(SLEEP),sleep如果沒執行完會返回剩下的秒數。
信號相關的知識點其實有很多,還需要大家在平時的使用中繼續深入研究。以上就是這篇文章的全部內容,希望能對大家有所幫助。