2009-11-01 12 views
7

Questo è qualcosa che mi sono chiesto per un po 'e ho deciso di chiedere al riguardo.PHP Check Process ID

Abbiamo la funzione getmypid() che restituirà l'id del processo degli script corrente. Esiste qualche tipo di funzione come

checkifpidexists() in php? Intendo uno integrato e non una soluzione di script batch.

E c'è un modo per modificare un pid di script?

Alcuni chiarimenti:

voglio verificare se un pid esiste per vedere se lo script è già in esecuzione in modo da Dont Run ancora una volta, job cron finto, se vuoi.

La ragione per cui volevo cambiare il pid è che posso impostare lo script pid su qualcosa di veramente alto come 60000 e il codice rigido che valore in modo che questo script possa essere eseguito solo su quel pid in modo che solo 1 istanza di esso venga eseguita

EDIT ----

per aiutare chiunque altro con questo proplem, ho creato questa classe:

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

} 

e si utilizza in questo modo:

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

risposta

17

In Linux, si guarderebbe/proc.

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

In Windows si poteva shell_exec() Tasklist.exe, e che sarebbe trovare un ID processo di corrispondenza:

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

Credo che ciò che si vuole fare è mantenere un file PID. Nei demoni che ho scritto, controllano un file di configurazione, cercano un'istanza di un file pid, estraggono il pid dal file pid, controllano se esiste/proc/$ pid e, in caso contrario, eliminano il pid file.

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

Gli ID processo sono concessi dal sistema operativo e non è possibile prenotare un ID processo. Scriveresti il ​​demone per rispettare il file pid.

+0

pcntl_fork() non cambierà il processo corrente pid! La funzione pcntl_fork() crea un processo figlio che differisce dal processo genitore solo nei suoi PID e PPID. Si prega di consultare la pagina man di fork del proprio sistema (2) per dettagli specifici su come funziona la forcella sul proprio sistema. – ennuikiller

+0

hmm, speravo in un modo più trasversale di verificare se esisteva un pid :( – Ozzy

+0

Con la mia modifica, ho accennato che non penso che voglia pcntl_fork(), né otterrebbe una scelta di pid –

1

No, non è possibile modificare alcun processo pid. Viene assegnato dal kernel e fa parte delle strutture dati del kernel

0

Come altri hanno già detto, non è possibile modificare l'id del processo, che è assegnato e interamente gestito dal kernel del sistema operativo. Inoltre, non hai detto se questo è basato su riga di comando o web-server: se è quest'ultimo, potresti non riuscire nemmeno a ottenere il pid del tuo script.

manual page for getmypid() contiene alcuni esempi di blocco "ottimistico". Uso la parola optimisitc in quanto PHP non accetterà mai l'applicazione web di asp.net in cui si ha un vero ambiente thread con classi condivise/statiche e quindi Singleton da usare/abusare. Fondamentalmente si ha la possibilità di:

  • Toccare un "file di blocco" sul file system da qualche parte. Lo script controlla quindi se quel file esiste: se lo fa, termina, altrimenti, tocca quel file e continua l'elaborazione
  • Impostazione di un flag basato sul database per dire che lo script è in esecuzione.Come sopra, ma usa una tabella/campo db per marcare uno script come in esecuzione.

Entrambi questi si basano sullo script che termina correttamente (come l'ultimo passo sarebbe quello di rimuovere il file di blocco/flag db). Se uno script si blocca per qualsiasi motivo (o per la macchina stessa), è possibile lasciare una procedura di ordine manuale per rimuovere il flag. Non c'è una soluzione facile per questo, ma una strada da esplorare sarebbe quella di guardare il blocco della data, con un approccio arbitrale "se più vecchio di X, l'ultima corsa deve essersi schiantato".

6

Un modo migliore per ottenere ciò consiste nell'utilizzare un pid o un file di blocco. Basta verificare l'esistenza del file pid, crearlo secondo necessità e popolarlo con il tuo pid in esecuzione.

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

e usarlo come segue:

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

Non c'è molto controllo degli errori qui, ma una corsa veloce mostra questo funziona sul mio sistema.

+0

Questo è il metodo utilizzato da molti daemon * nix. – Jason

1

Per verificare se un PID esiste su una macchina Windows che uso:

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

Nota che $ outputB [0] contiene un messaggio che PID non può essere trovato , se il pid in effetti non esiste! Quindi per validare uso il secondo argomento.