2009-11-01 75 views
7

這是我想了一會兒,並決定問一下。PHP檢查過程ID

我們有函數getmypid(),它將返回當前腳本進程ID。是否有某種功能在PHP如

checkifpidexists()?我的意思是一個內置的而不是一些批處理腳本解決方案。

有沒有辦法更改腳本pid?

一些澄清:

我想檢查是否存在PID,看看,如果你願意的腳本已經運行,因此不要再次運行,人造cron作業。

我想改變PID的原因是這樣我就可以設置腳本PID的東西實在是高,如60000,硬代碼看重因此該腳本只能在運行的pid所以只1它的實例可以運行

編輯----

爲了幫助別人與此proplem,我創建了這個類:

class instance { 

    private $lock_file = ''; 
    private $is_running = false; 

    public function __construct($id = __FILE__) { 

     $id = md5($id); 

     $this->lock_file = sys_get_temp_dir() . $id; 

     if (file_exists($this->lock_file)) { 
      $this->is_running = true; 
     } else { 
      $file = fopen($this->lock_file, 'w'); 
      fclose($file); 
     } 
    } 

    public function __destruct() { 
     if (file_exists($this->lock_file) && !$this->is_running) { 
      unlink($this->lock_file); 
     } 
    } 

    public function is_running() { 
     return $this->is_running; 
    } 

} 

,並使用它像這樣:

$instance = new instance('abcd'); // the argument is optional as it defaults to __FILE__ 

if ($instance->is_running()) { 
    echo 'file already running';  
} else { 
    echo 'file not running'; 
} 

回答

17

在linux中,你會看/ proc。

return file_exists("/proc/$pid"); 

在Windows中,你可以了shell_exec()tasklist.exe,這將找到一個匹配的進程ID:

$processes = explode("\n", shell_exec("tasklist.exe")); 
foreach($processes as $process) 
{ 
    if(strpos("Image Name", $process) === 0 
     || strpos("===", $process) === 0) 
      continue; 
    $matches = false; 
    preg_match("/(.*?)\s+(\d+).*$/", $process, $matches); 
    $pid = $matches[ 2 ]; 
} 

我相信你想要做的是保持一個PID文件。在我編寫的守護進程中,他們檢查配置文件,查找pid文件的實例,從pid文件中獲取pid,檢查/ proc/$ pid是否存在,如果不存在,則刪除pid文件。

if(file_exists("/tmp/daemon.pid")) 
    { 
     $pid = file_get_contents("/tmp/daemon.pid"); 
     if(file_exists("/proc/$pid")) 
     { 
      error_log("found a running instance, exiting."); 
      exit(1); 
     } 
     else 
     { 
      error_log("previous process exited without cleaning pidfile, removing"); 
      unlink("/tmp/daemon.pid"); 
     } 
    } 
    $h = fopen("/tmp/daemon.pid", 'w'); 
    if($h) fwrite($h, getmypid()); 
    fclose($h); 

進程ID由操作系統授予,但無法保留進程ID。你會寫你的守護進程來尊重pid文件。

+0

pcntl_fork()將不會改變當前進程的PID! pcntl_fork()函數僅在其PID和PPID中創建一個與父進程不同的子進程。請參閱系統的fork(2)手冊頁,以獲取有關fork如何在您的系統上工作的具體細節。 – ennuikiller

+0

嗯,我希望的,如果PID存在:( – Ozzy

+0

隨着我的編輯檢查的更多的跨操作系統的方式,我提到我不認爲他想pcntl_fork(),也不是他會得到的PID選擇。 –

1

不,您不能更改任何進程pid。它是由內核分配的,是內核數據結構

的一部分
0

正如其他人所說,你不能改變的進程ID - 它被分配並通過OS的內核完全manged。另外,您還沒有說過,如果這是基於命令行或基於Web的服務器:如果是後者,您甚至可能不會獲得腳本的pid。

manual page for getmypid()包含「樂觀」鎖定的一些例子。我使用optimisitc這個詞,因爲PHP永遠不會接近像asp.net web應用程序這樣的應用程序,在這個應用程序中你有一個真正的帶有共享/靜態類的線程環境,因此Singleton可以使用/濫用。基本上你可以選擇:

  • 在文件系統的某處觸摸「鎖定文件」。然後你的腳本檢查該文件是否存在:如果存在,終止,否則,觸摸該文件並進行處理
  • 設置基於數據庫的標誌來表示腳本正在運行。如上所述,但使用db table/field將腳本標記爲正在運行。

這兩者都依賴於腳本正確終止(作爲最後一步將刪除鎖定文件/數據庫標誌)。如果一個腳本崩潰因任何原因(或機器本身),你可以用手工整理,過程留給刪除標誌。目前對此沒有簡單的解決方案,而是一個途徑,探索將再看看日期衝壓鎖,用arbitary「如果不是X年紀大了,上一次運行必須墜毀」的做法。

6

一種更好的方式來完成,這將是使用PID或鎖定文件。只需檢查是否存在pid文件,根據需要創建它,然後使用正在運行的pid填充它。

<? 
    class pidfile { 
    private $_file; 
    private $_running; 

    public function __construct($dir, $name) { 
     $this->_file = "$dir/$name.pid"; 

     if (file_exists($this->_file)) { 
     $pid = trim(file_get_contents($this->_file)); 
     if (posix_kill($pid, 0)) { 
      $this->_running = true; 
     } 
     } 

     if (! $this->_running) { 
     $pid = getmypid(); 
     file_put_contents($this->_file, $pid); 
     } 
    } 

    public function __destruct() { 
     if ((! $this->_running) && file_exists($this->_file)) { 
     unlink($this->_file); 
     } 
    } 

    public function is_already_running() { 
     return $this->_running; 
    } 
    } 
?> 

而且按如下方式使用它:

<? 
    $pidfile = new pidfile('/tmp', 'myscript'); 
    if($pidfile->is_already_running()) { 
    echo "Already running.\n"; 
    exit; 
    } else { 
    echo "Started...\n"; 
    } 
?> 

沒有太多的錯誤檢查在這裏,但一個快速運行顯示了這個作品在我的系統上。

+0

這是很多* nix守護進程使用的方法。 – Jason

1

爲了檢查當PID的Windows機器上存在我使用:

function pidExists($pid) 
{ 
    exec('TASKLIST /NH /FO "CSV" /FI "PID eq '.$pid.'"', $outputA); 
    $outputB = explode('","', $outputA[0]); 
    return isset($outputB[1])?true:false; 
} 

注意$ OUTPUTB [0]包含的pid無法找到一個消息,如果pid確實不存在!所以要驗證我使用第二個參數。