2009-11-01 42 views
7

Đây là điều tôi đã tự hỏi một lúc và quyết định hỏi về nó.Quy trình kiểm tra PHP ID

Chúng tôi có hàm getmypid() sẽ trả về id quá trình tập lệnh hiện tại. Có một số loại chức năng như

checkifpidexists() trong php? Tôi có nghĩa là một sẵn có và không phải là một số giải pháp hàng loạt kịch bản.

Và có cách nào để thay đổi tập lệnh pid không?

Một số làm rõ:

tôi muốn kiểm tra xem một pid tồn tại để xem nếu kịch bản vẫn đang chạy nên nó không chạy lại, công việc định kỳ giả nếu bạn sẽ. Lý do tôi muốn thay đổi pid là vì vậy tôi có thể thiết lập các pid script để một cái gì đó thực sự cao như 60000 và mã cứng có giá trị để kịch bản này chỉ có thể chạy trên pid đó để chỉ có 1 trường hợp của nó sẽ chạy

EDIT ----

Để giúp bất cứ ai khác với proplem này, tôi đã tạo ra lớp này:

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; 
    } 

} 

và bạn sử dụng nó như vậy:

$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'; 
} 

Trả lời

17

Trong linux, bạn sẽ xem/proc.

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

Trong Windows bạn có thể shell_exec() tasklist.exe, và đó sẽ tìm thấy một quá trình hợp 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 ]; 
} 

Tôi tin rằng những gì bạn muốn làm là duy trì một tập tin PID. Trong daemon tôi đã viết, họ kiểm tra một tập tin cấu hình, tìm một thể hiện của một tập tin pid, lấy pid ra khỏi tập tin pid, kiểm tra xem nếu proc/$ pid tồn tại, và nếu không, xóa pid tập tin.

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 quy trình được hệ điều hành cấp và người dùng không thể đặt trước id quá trình. Bạn sẽ viết daemon của bạn để tôn trọng tệp pid.

+0

pcntl_fork() sẽ không thay đổi các quy trình hiện tại pid! Hàm pcntl_fork() tạo ra một tiến trình con khác với tiến trình cha chỉ trong PID và PPID của nó. Vui lòng xem trang nhánh (2) dành cho người đàn ông của hệ thống của bạn để biết chi tiết cụ thể về cách hoạt động của hệ thống của bạn. – ennuikiller

+0

hmm, tôi đã hy vọng một cách vượt trội hơn để kiểm tra nếu một pid tồn tại: ( – Ozzy

+0

Với chỉnh sửa của tôi, tôi đề cập đến tôi không nghĩ rằng anh ta muốn pcntl_fork(), cũng không có được sự lựa chọn của pid –

1

Không, bạn không thể thay đổi bất kỳ quy trình nào. Nó được gán bởi hạt nhân và là một phần của cấu trúc dữ liệu của hạt nhân

0

Như những người khác đã nói, bạn không thể thay đổi id tiến trình - nó được gán và hoàn toàn mang bởi hạt nhân của hệ điều hành. Ngoài ra, bạn đã không nói nếu đây là dòng lệnh hoặc máy chủ web dựa trên: nếu đó là sau này bạn có thể thậm chí không nhận được pid của kịch bản của bạn.

manual page for getmypid() chứa một số ví dụ về khóa "lạc quan". Tôi sử dụng từ optimisitc như PHP là không bao giờ bao giờ sẽ tiếp cận các thích của một ứng dụng web asp.net nơi bạn có một môi trường threaded đúng với các lớp học chia sẻ/tĩnh và do đó Singleton sử dụng/lạm dụng. Về cơ bản, bạn có tùy chọn:

  • Chạm vào "tệp khóa" trên hệ thống tệp ở đâu đó. Tập lệnh của bạn sau đó kiểm tra xem tệp đó có tồn tại hay không: nếu có, chấm dứt, nếu không, hãy chạm vào tệp đó và tiếp tục xử lý
  • Đặt cờ dựa trên cơ sở dữ liệu để nói tập lệnh đang chạy.Như trên, nhưng sử dụng một bảng/trường db để đánh dấu một tập lệnh đang chạy.

Cả hai đều dựa vào tập lệnh chấm dứt chính xác (vì bước cuối cùng là xóa cờ khóa/tệp db). Nếu một kịch bản bị treo vì bất kỳ lý do nào (hoặc chính bản thân máy), bạn có thể bị bỏ lại bằng một quy trình dọn dẹp thủ công để xóa cờ. Không có giải pháp dễ dàng cho việc này, nhưng một con đường để khám phá sẽ là sau đó nhìn vào ngày dán tem khóa, với một lệnh cấm "nếu lớn hơn X, chạy cuối cùng phải đã bị rơi" phương pháp tiếp cận.

6

Cách tốt hơn để thực hiện việc này là sử dụng tệp pid hoặc khóa. Chỉ cần kiểm tra sự tồn tại của tệp pid, tạo nó khi cần thiết và điền nó với pid đang chạy của bạn.

<? 
    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; 
    } 
    } 
?> 

Và sử dụng nó như sau:

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

Không có nhiều lỗi kiểm tra ở đây, nhưng một cách nhanh chóng cho thấy công trình này trên hệ thống của tôi.

+0

Đây là phương pháp mà nhiều trình nền * nix sử dụng. – Jason

1

Đối với kiểm tra nếu một PID tồn tại trên một máy cửa sổ tôi sử dụng:

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

Lưu ý rằng $ outputB [0] chứa một thông điệp rằng pid không thể được tìm thấy , nếu pid thực sự không tồn tại! Vì vậy, để xác nhận tôi sử dụng đối số thứ hai.

Các vấn đề liên quan