在pnctl系列函數(shù)中,可以給信號創(chuàng)建處理器,當(dāng)子進(jìn)程退出或產(chǎn)生其它信號時,將不同的信號分配給指定的處理器,讓程序更加靈活高效。
常用的有這三個函數(shù)
| 函數(shù) | 說明 |
|---|---|
| pcntl_signal | 安裝信號處理器 |
| pcntl_signal_dispatch | 等待接收信號并調(diào)用信號處理器方法 |
| pcntl_async_signals | 啟用異步信號處理,收到信號時就可以立即調(diào)用處理程序 |
另外在介紹三個經(jīng)常使用的與操作系統(tǒng)交互的函數(shù),它們是posix模塊的
| 函數(shù) | 說明 |
|---|---|
| posix_getpid | 返回當(dāng)前進(jìn)程的id |
| posix_getppid | 返回父進(jìn)程的id |
| posix_kill | 給指定進(jìn)程發(fā)送信號 |
1.創(chuàng)建信號處理器
pcntl_signal(SIGCHLD,[self::class,'handleSignal']);
使用pcntl_signal函數(shù)可以給指定的信號創(chuàng)建處理器,在程序里,給SIGCHLD信號指定處理器。 SIGCHLD 代表子進(jìn)程退出
參數(shù)1填寫信號常量,在本文第三段落介紹。
參數(shù)2:填寫處理器,它有多種寫法,如果是在腳本里寫,可以填寫處理方法的名字,也可以用閉包的形式
pcntl_signal(SIGCHLD,'handleSignal');
pcntl_signal(SIGCHLD,function($signo){
//signo 是自定義的變量,用于接收信號
});
如果是在類文件里使用,參數(shù)2使用閉包或靜態(tài)方法,這個代碼就是用的靜態(tài)方法。
pcntl_signal(SIGCHLD,[self::class,'handleSignal']);
回收資源方法代碼
private static function handleSignal($signo){
switch($signo){
case SIGCHLD:
while(($childPid = pcntl_waitpid(-1,$status,WNOHANG)) > 0){
$key = array_search($childPid,self::$pidPool);
if($key !== false){
unset(self::$pidPool[$key]);
}
Log::channel('wechat')->debug('子進(jìn)程已經(jīng)被回收',[
'childPid'=>$childPid,
'ppid'=>posix_getppid(),
'total'=>count(self::$pidPool)
]);
}
break;
}
}
使用switch結(jié)構(gòu),來判斷$signo 是哪種信號,進(jìn)而寫出單獨(dú)的處理邏輯代碼。
2 接收信號并分配給處理器
當(dāng)創(chuàng)建多個子進(jìn)程,每個子進(jìn)程退出后,需要接收退出信號,并分配給處理器,可以使用 pcntl_signal_dispatch 進(jìn)行同步接收。
while(true){
pcntl_signal_dispatch();
sleep(1);
}
pcntl_signal_dispatch() 它是一個同步函數(shù),必須放到while里,寫一個死循環(huán)來監(jiān)控,每收到一個退出的信號時,就進(jìn)行分配。
如果覺得麻煩,可以使用異步信號處理程序。 在程序頂部,pcntl_async_signals(true)函數(shù)可以執(zhí)行異步接收,參數(shù)一定要使用 true 如果用 false還是同步接收。
//啟用異步接收信號,收到信號立即調(diào)用處理程序
pcntl_async_signals(true);
pcntl_signal(SIGCHLD,[self::class,'handleSignal']);
3.需要記住的信號編號
| 信號 | 說明 |
|---|---|
| SIGTERM | 終止信號。用于請求程序正常終止??梢员徊东@、阻塞或忽略。通常用于友好地結(jié)束進(jìn)程。 |
| SIGKILL | 殺死信號。用于強(qiáng)制終止進(jìn)程,不能被捕獲、阻塞或忽略。是終止進(jìn)程的最后手段。 |
| SIGINT | 中斷信號。通常在用戶按下 Ctrl + C 時發(fā)送,用于終止前臺運(yùn)行的進(jìn)程。 |
| SIGHUP | 掛起信號。通常在終端斷開時發(fā)送給控制終端上的進(jìn)程,常用于重新加載配置文件或重新啟動進(jìn)程。 |
| SIGQUIT | 退出信號。與 SIGINT 類似,但由 Ctrl + \ 觸發(fā),并且會生成核心轉(zhuǎn)儲。 |
| SIGSTOP | 停止信號。無條件地暫停進(jìn)程的執(zhí)行。不能被捕獲或忽略,通常用在調(diào)試和作業(yè)控制。 |
| SIGCONT | 繼續(xù)信號。用于恢復(fù)暫停的進(jìn)程,可以被捕獲或忽略,用于調(diào)試和作業(yè)控制。 |
| SIGUSR1 和 SIGUSR2 | 用戶定義的信號。通常用于用戶自定義的處理,可以在應(yīng)用程序中捕獲并執(zhí)行特定的操作。 |
| SIGALRM | 鬧鐘信號。用于定時器到期通知,通常與 alarm() 系統(tǒng)調(diào)用一起使用。 |
| SIGPIPE | 管道破裂信號。當(dāng)向一個沒有讀端的管道或 FIFO 寫入數(shù)據(jù)時,會觸發(fā)這個信號,通常用于通知進(jìn)程寫入失敗。 |
| SIGCHLD | 當(dāng)子進(jìn)程的狀態(tài)發(fā)生變化時(如子進(jìn)程退出、停止、繼續(xù)等),內(nèi)核會向父進(jìn)程發(fā)送 SIGCHLD 信號。這種信號通知父進(jìn)程有一個子進(jìn)程狀態(tài)變化的事件發(fā)生,使得父進(jìn)程可以處理子進(jìn)程的退出狀態(tài),避免產(chǎn)生僵尸進(jìn)程(Zombie Process)。 |