多進(jìn)程開發(fā)2:使用信號模式回收資源

在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)。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容