2009-11-01 9 views
7

To jest coś, przez co zastanawiałem się przez chwilę i postanowiłem o to zapytać.PHP Check Process ID

Mamy funkcję getmypid(), która zwróci bieżący identyfikator procesu skryptu. Czy jest jakaś funkcja, taka jak

checkifpidexists() w php? Mam na myśli rozwiązanie wbudowane, a nie jakieś rozwiązanie skryptu wsadowego.

A czy istnieje sposób na zmianę skryptu pid?

Niektóre wyjaśnienia:

Chcę sprawdzić, czy istnieje PID aby sprawdzić, czy skrypt działa już tak dont uruchomić ponownie, faux crona jeśli będzie.

Powodem, dla którego chciałem zmienić pid jest to, że mogę ustawić pid skryptu na coś naprawdę wysokiego, takiego jak 60000 i twardy kod, którego wartość, więc ten skrypt może działać tylko na tym pidzie, więc tylko 1 wystąpienie tego byłoby uruchomione

EDIT ----

Aby pomóc nikogo innego z tego proplem, Stworzyłem tę klasę:

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

} 

i go używać tak:

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

Odpowiedz

17

W systemie Linux, należy spojrzeć na/proc.

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

W systemie Windows można shell_exec() tasklist.exe, i że będzie znaleźć identyfikator procesu dopasowywania:

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

wierzę, co chcesz zrobić, to zachować plik PID. W demonach, które napisałem, sprawdzają plik konfiguracyjny, szukają przykładu pliku pid, pobierają pid z pliku pid, sprawdzają, czy istnieje/proc/$ pid, a jeśli nie, usuń pid plik.

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

Identyfikatory procesów są przyznawane przez system operacyjny i nie można zarezerwować identyfikatora procesu. Napisałbyś swojego demona, by szanował plik pid.

+0

pcntl_fork() nie zmieni bieżącego procesu pid! Funkcja pcntl_fork() tworzy proces podrzędny, który różni się od procesu nadrzędnego tylko w jego PID i PPID. Zobacz stronę podręcznika systemowego fork (2) systemu, aby uzyskać szczegółowe informacje na temat działania wideł w systemie. – ennuikiller

+0

hmm, miałem nadzieję na lepszy sposób sprawdzania, czy pid istniał :( – Ozzy

+0

Z moją edycją wspomniałem, że nie myślę, że chce on pcntl_fork(), ani nie dostanie wyboru pid. –

1

Nie można zmienić żadnego procesu pid. Jest on przypisany przez jądro i jest częścią struktur danych jądra

0

Jak mówili inni, nie można zmienić identyfikator procesu - jest przypisywany i całkowicie manged przez jądro systemu operacyjnego. Ponadto nie powiedziałeś, czy jest to oparte na wierszu poleceń, czy na serwerze internetowym: jeśli to drugie, możesz nawet nie dostać pid swojego skryptu.

manual page for getmypid() zawiera kilka przykładów „optymistycznego” Blokowanie. Używam słowa optimisitc, ponieważ PHP nigdy nie będzie zbliżać się do takiej aplikacji internetowej asp.net, w której istnieje prawdziwe środowisko z klasami współdzielonymi/statycznymi, a tym samym Singleton używa/nadużywa. Zasadniczo masz opcję:

  • Dotknięcie "pliku blokady" w systemie plików gdzieś. Twój skrypt sprawdza, czy plik istnieje: jeśli tak, zamknij, w przeciwnym razie dotknij tego pliku i kontynuuj przetwarzanie Ustawiając flagę opartą na bazie danych, powiedz, że skrypt jest uruchomiony.Jak wyżej, ale użyj tabeli/pola db, aby oznaczyć skrypt jako uruchomiony.

Obie te opcje polegają na poprawnym zakończeniu skryptu (jako że ostatnim krokiem byłoby usunięcie pliku blokady/flagi db). Jeśli skrypt zostanie zawieszony z jakiegokolwiek powodu (lub samego komputera), możesz pozostawić ręczny proces czyszczenia, aby usunąć flagę. Nie ma na to łatwego rozwiązania, ale jedną z dróg do zbadania byłoby obejrzenie pieczęci z datą, z arbitralnym podejściem "jeśli starsze niż X, ostatnia droga musiało się rozbić".

6

Lepszym sposobem na osiągnięcie tego byłoby użycie pid lub pliku blokady. Po prostu sprawdź, czy istnieje plik pid, utwórz go w razie potrzeby i zapełnij go bieżącym pidem.

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

i używać go w sposób następujący:

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

Niewiele sprawdzanie błędów tutaj, ale szybki bieg pokazuje to działa w moim systemie.

+0

Jest to metoda używana przez wiele demonów * nix. – Jason

1

Do sprawdzania, czy PID istnieje na komputerze z systemem Windows używam:

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

Zauważ, że $ OUTPUTB [0] zawiera wiadomości, które PID nie można znaleźć , jeśli pid rzeczywiście nie istnieje! Aby sprawdzić poprawność używam drugiego argumentu.