這篇文章主要介紹PHP多進(jìn)程與信號(hào)中斷實(shí)現(xiàn)多任務(wù)常駐內(nèi)存管理的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!
我們提供的服務(wù)有:網(wǎng)站設(shè)計(jì)、做網(wǎng)站、微信公眾號(hào)開發(fā)、網(wǎng)站優(yōu)化、網(wǎng)站認(rèn)證、海陵ssl等。為上千家企事業(yè)單位解決了網(wǎng)站和推廣的問題。提供周到的售前咨詢和貼心的售后服務(wù),是有科學(xué)管理、有技術(shù)的海陵網(wǎng)站制作公司
進(jìn)程調(diào)度策略
父子進(jìn)程的調(diào)度由操作系統(tǒng)來負(fù)責(zé),具體先調(diào)度子進(jìn)程還是父進(jìn)程由系統(tǒng)的調(diào)度算法決定,當(dāng)然可以在父進(jìn)程加上延時(shí)或是調(diào)用進(jìn)程回收函數(shù) pcntl_wait 可以先讓子進(jìn)程先運(yùn)行,進(jìn)程回收的目的是釋放進(jìn)程創(chuàng)建時(shí)占用的內(nèi)存空間,防止變成僵尸進(jìn)程。
信號(hào):
信號(hào)稱為軟中斷系統(tǒng)或是叫軟中斷,功能是向進(jìn)程發(fā)送異步事件通知。
信號(hào)編號(hào):【源碼基于 SIGINT,SIGTERM,SIGUSR1 信號(hào),含義請(qǐng)自行查看 kill 命令手冊(cè),不在描述】
linux 支持 64 個(gè),有一半為實(shí)時(shí)信號(hào),一半為非時(shí)實(shí)信號(hào),這些信號(hào)都有自己的編號(hào)和對(duì)應(yīng)的整數(shù)值。每個(gè)信號(hào)的編號(hào)含義讀者可以參閱 linux 相關(guān)手冊(cè)【man 手冊(cè)看看就知道了】
信號(hào)處理函數(shù):
信號(hào)一般會(huì)綁定相應(yīng)的功能,有的是默認(rèn)動(dòng)作如 SIGKILL,SIGTERM,SIGINT 操作默認(rèn)操作就是干掉進(jìn)程,當(dāng)然我們可以重寫覆蓋掉,就是通過 pcntl_signal 來覆蓋掉。
信號(hào)的概念:與硬件中斷一個(gè)道理,請(qǐng)讀者自行參考本人前面擼過的文章或是查看芯片硬件中斷原理。
信號(hào)的發(fā)送:
kill 信號(hào)編號(hào) 進(jìn)程 或是按鍵產(chǎn)品的中斷信號(hào)或是在源碼里可以使用 posix_kill 等函數(shù)。
進(jìn)程是相互隔離的,擁有自己的堆??臻g,除了一些公用的正文【代碼區(qū)】,同時(shí)也有自己的可執(zhí)行代碼,進(jìn)程運(yùn)行時(shí),將占用 cpu 的資源,其它進(jìn)程將無權(quán)運(yùn)行,此時(shí)其它進(jìn)程將為阻塞狀態(tài)【比如前面擼過的 tcp 服務(wù)】,當(dāng)進(jìn)程運(yùn)行結(jié)束后【運(yùn)行到代碼的最后一句或是遇到 return 或是遇到 exit 退出進(jìn)程函數(shù)或是遇到信號(hào)事件時(shí)將會(huì)退出】讓出權(quán)限并釋放掉內(nèi)存,其它進(jìn)程就有機(jī)會(huì)運(yùn)行了。
進(jìn)程擁有的自己進(jìn)程描述符,其中比較常用的是進(jìn)程號(hào) PID,進(jìn)程運(yùn)行時(shí)會(huì)在系統(tǒng) /proc/PID 下生成相應(yīng)的進(jìn)程文件,用戶可以自行查看。
每個(gè)進(jìn)程都擁有所屬的進(jìn)程組【進(jìn)程的集合】,多個(gè)進(jìn)程組集合則是一個(gè)會(huì)話,創(chuàng)建一個(gè)會(huì)話是通過一個(gè)進(jìn)程進(jìn)行創(chuàng)建的,并且此進(jìn)程不可以為組長(zhǎng)進(jìn)程,此進(jìn)程將成為會(huì)話期的會(huì)話首進(jìn)程,也會(huì)成為進(jìn)程組的進(jìn)程組長(zhǎng),同時(shí)將會(huì)脫離控制終端,即使之前的進(jìn)程綁定了控制終端也會(huì)脫離【守護(hù)進(jìn)程的創(chuàng)建】。
文件描述權(quán)限掩碼【權(quán)限屏蔽字】:
umask () 你可以在 linux 運(yùn)行這個(gè)命令,然后創(chuàng)建文件,并查看它的權(quán)限【如果你跑完啥也沒有發(fā)現(xiàn),說明你還是訓(xùn)練不夠 ^_^】
daemon(); $this->worker(); $this->setMasterPid(); $this->installSignal(); $this->showState(); $this->wait(); } function wait() { while (1){ pcntl_signal_dispatch(); $pid = pcntl_wait($status); if ($pid>0){ unset($this->workerPids[$pid]); }else{ if (count($this->workerPids)==0){ exit(); } } usleep(100000); } } function showState() { $state = "\nMaster 信息\n"; $state.=str_pad("master pid",25); $state.=str_pad("worker num",25); $state.=str_pad("job pid list",10)."\n"; $state.=str_pad($this->getMasterPid(),25); $state.=str_pad(count($this->workerPids),25); $state.=str_pad(implode(",",array_keys($this->workerPids)),10); echo $state.PHP_EOL; } function getMasterPid() { if (file_exists($this->master_pid_file)){ return file_get_contents($this->master_pid_file); }else{ exit("服務(wù)未運(yùn)行\(zhòng)n"); } } function setMasterPid() { $fp = fopen($this->master_pid_file,"w"); @fwrite($fp,posix_getpid()); @fclose($fp); } function daemon() { $pid = pcntl_fork(); if ($pid<0){ exit("fork進(jìn)程失敗\n"); }else if ($pid >0){ exit(0); }else{ umask(0); $sid = posix_setsid(); if ($sid<0){ exit("創(chuàng)建會(huì)話失敗\n"); } $pid = pcntl_fork(); if ($pid<0){ exit("進(jìn)程創(chuàng)建失敗\n"); }else if ($pid >0){ exit(0); } //可以關(guān)閉標(biāo)準(zhǔn)輸入輸出錯(cuò)誤文件描述符【守護(hù)進(jìn)程不需要】 } } function worker() { if (count($this->workerJob)==0)exit("沒有工作任務(wù)\n"); foreach($this->workerJob as $job){ $pid = pcntl_fork(); if ($pid<0){ exit("工作進(jìn)程創(chuàng)建失敗\n"); }else if ($pid==0){ /***************子進(jìn)程工作范圍**********************/ //給子進(jìn)程安裝信號(hào)處理程序 $this->workerInstallSignal(); $start_time = time(); while (1){ pcntl_signal_dispatch(); if ((time()-$start_time)>=$job->job_run_time){ break; } $job->run(posix_getpid()); } exit(0);//子進(jìn)程運(yùn)行完成后退出 /***************子進(jìn)程工作范圍**********************/ }else{ $this->workerPids[$pid] = $job; } } } function workerInstallSignal() { pcntl_signal(SIGUSR1,[__CLASS__,'workerHandleSignal'],false); } function workerHandleSignal($signal) { switch ($signal){ case SIGUSR1: $state = "worker pid=".posix_getpid()."接受了父進(jìn)程發(fā)來的自定義信號(hào)\n"; file_put_contents($this->state_file,$state,FILE_APPEND); break; } } function installSignal() { pcntl_signal(SIGINT,[__CLASS__,'handleMasterSignal'],false); pcntl_signal(SIGTERM,[__CLASS__,'handleMasterSignal'],false); pcntl_signal(SIGUSR1,[__CLASS__,'handleMasterSignal'],false); } function handleMasterSignal($signal) { switch ($signal){ case SIGINT: //主進(jìn)程接受到中斷信號(hào)ctrl+c foreach ($this->workerPids as $pid=>$worker){ posix_kill($pid,SIGINT);//向所有的子進(jìn)程發(fā)出 } exit("服務(wù)平滑停止\n"); break; case SIGTERM://ctrl+z foreach ($this->workerPids as $pid=>$worker){ posix_kill($pid,SIGKILL);//向所有的子進(jìn)程發(fā)出 } exit("服務(wù)停止\n"); break; case SIGUSR1://用戶自定義信號(hào) if (file_exists($this->state_file)){ unlink($this->state_file); } foreach ($this->workerPids as $pid=>$worker){ posix_kill($pid,SIGUSR1); } $state = "master pid\n".$this->getMasterPid()."\n"; while(!file_exists($this->state_file)){ sleep(1); } $state.= file_get_contents($this->state_file); echo $state.PHP_EOL; break; } } } workerJob = [new \Chen\Worker\Talk(),new \Chen\Worker\Job()]; $process->run();
以上是“PHP多進(jìn)程與信號(hào)中斷實(shí)現(xiàn)多任務(wù)常駐內(nèi)存管理的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道!