溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

PHP多進(jìn)程與信號(hào)中斷實(shí)現(xiàn)多任務(wù)常駐內(nèi)存管理的示例分析

發(fā)布時(shí)間:2021-01-28 11:08:27 來(lái)源:億速云 閱讀:229 作者:小新 欄目:編程語(yǔ)言

這篇文章主要介紹PHP多進(jìn)程與信號(hào)中斷實(shí)現(xiàn)多任務(wù)常駐內(nèi)存管理的示例分析,文中介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們一定要看完!

進(jìn)程調(diào)度策略

父子進(jìn)程的調(diào)度由操作系統(tǒng)來(lái)負(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)然我們可以重寫覆蓋掉,就是通過(guò) pcntl_signal 來(lái)覆蓋掉。

信號(hào)的概念:與硬件中斷一個(gè)道理,請(qǐng)讀者自行參考本人前面擼過(guò)的文章或是查看芯片硬件中斷原理。

信號(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)程將無(wú)權(quán)運(yùn)行,此時(shí)其它進(jìn)程將為阻塞狀態(tài)【比如前面擼過(guò)的 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ì)話是通過(guò)一個(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)限【如果你跑完啥也沒(méi)有發(fā)現(xiàn),說(shuō)明你還是訓(xùn)練不夠 ^_^】

<?php
/**
 * Created by PhpStorm.
 * User: 1655664358@qq.com
 * Date: 2018/3/26
 * Time: 14:19
 */
namespace Chen\Worker;
class Server
{
    public $workerPids = [];
    public $workerJob = [];
    public $master_pid_file = "master_pid";
    public $state_file = "state_file.txt";
    function run()
    {
        $this->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("沒(méi)有工作任務(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ā)來(lái)的自定義信號(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;
        }
    }
}  
<?php
/**\
 * Created by PhpStorm.\ * User: 1655664358@qq.com
 * Date: 2018/3/26\ * Time: 14:37\ */\namespace Chen\Worker;
class Job
{
  public $job_run_time = 3600;
  function run($pid)
 {\sleep(3);
  echo "worker pid = $pid job 沒(méi)事干,就在這里job\n";
  }
}  
<?php
/**
 * Created by PhpStorm.\ * User: 1655664358@qq.com
 * Date: 2018/3/26\ * Time: 14:37\ */\namespace Chen\Worker;
class Talk
{
  public $job_run_time = 3600;
  function run($pid)
 {\sleep(3);
  echo "worker pid = $pid job 沒(méi)事干,就在這里talk\n";
  }
}
<?php
/**
 * Created by PhpStorm.\ * User: 1655664358@qq.com
 * Date: 2018/3/26\ * Time: 15:45\ */
require_once 'vendor/autoload.php';
$process = new \Chen\Worker\Server();
$process->workerJob = [new \Chen\Worker\Talk(),new \Chen\Worker\Job()];
$process->run();

PHP多進(jìn)程與信號(hào)中斷實(shí)現(xiàn)多任務(wù)常駐內(nèi)存管理的示例分析

以上是“PHP多進(jìn)程與信號(hào)中斷實(shí)現(xiàn)多任務(wù)常駐內(nèi)存管理的示例分析”這篇文章的所有內(nèi)容,感謝各位的閱讀!希望分享的內(nèi)容對(duì)大家有幫助,更多相關(guān)知識(shí),歡迎關(guān)注億速云行業(yè)資訊頻道!

向AI問(wèn)一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI