PHP系統編程--02.PHP守護進程化

什麼是守護進程?

一個守護進程一般補認爲是一個不對終端進行控制的後臺任務。它有三個很顯著的特徵:在後臺運行,與啓動他的進程脫離,無須控制終端。經常使用的實現方式是fork() -> setsid() -> fork()php

在glibc裏有一個函數daemon。調用此函數,就可以使當前進程脫離終端變成一個守護進程,具體內容參見man daemon。PHP中暫時沒有此函數,PHP程序實現守護進程化有2種方法:session

使用系統命令nohup

nohup php myprog.php > log.txt &函數

&,這樣執行程序雖然也是轉爲後臺運行,但其實是依賴終端的,當用戶退出終端時進程就會被殺掉。須要使用nohup來實現code

PHP腳本函數實現:

<?php
function daemon()
{
    $pid = pcntl_fork();
    if($pid < 0){
        die("fork(1) failed!\n");
    }elseif($pid > 0){
        exit; //讓終端啓動的進程退出
    }
     chdir("/"); //改變當前目錄爲根目錄
    umask(0); //重設文件權限掩碼
    //創建一個有別於終端的新session以脫離終端
    $sid = posix_setsid();
    if (!$sid) {
        die("setsid failed!\n");
    }
    $pid = pcntl_fork();
    if($pid < 0){
        die("fork(1) failed!\n");
    }elseif($pid > 0){
        exit; //父進程退出, 剩下子進程成爲最終的獨立進程
    }
    //關閉標準I/O流
    if (defined('STDIN')) {
        fclose(STDIN);
    }
    if (defined('STDOUT')){
        fclose(STDOUT);
    }
    if (defined('STDERR')) {
        fclose(STDERR);
    }
}
daemon();
sleep(1000);

這裏較爲關鍵的二個php函數是pcntl_fork()和posix_setsid()繼承

  • fork()一個進程,則表示建立了一個運行進程的副本,副本被認爲是子進程,而原始進程被認爲是父進程。當fork()運行以後,則能夠脫離啓動他的進程與終端控制等,也意味着父進程能夠自由退出。
  • setsid(),它首先使新進程成爲一個新會話的「領導者」,最後使該進程再也不控制終端,這也是成爲守護進程最關鍵的一步,這意味着,不會隨着終端關閉而強制退出進程。對於一個不會被中斷的常駐進程來講,這是很關鍵的一步。
  • 進行最後一次fork(),這一步不是必須的,但一般都這麼作,它最大的意義是防止得到控制終端。(在直接打開一個終端設備,並且沒有使用O_NOCTTY標誌的狀況下, 會得到控制終端)

其它事項說明:進程

  • chdir() 守護進程默認繼承了父進程的當前工做目錄,當系統磁盤發生umount時將形成諸多的麻煩,一般將」/」 做爲守護進程的當前工做目錄,能夠避免上述的問題
  • umask() 守護進程默認繼承了父進程的文件權限掩碼,這就給該子進程使用文件帶來了諸多的麻煩。所以,把文件權限掩碼設置爲0,能夠大大加強該守護進程的靈活性
  • fclose(STDIN), fclose(STDOUT), fclose(STDERR) 關閉標準I/O流。用fork函數新建的子進程會從父進程那裏繼承一些已經打開了的文件。這些被打開的文件可能永遠不會被守護進程讀寫,但它們同樣消耗系統資源,並且可能致使所在的文件系統沒法卸下。



相關文章
相關標籤/搜索