2009-11-01 30 views
7

Esto es algo que me he preguntado por un tiempo y decidí preguntar al respecto.PHP Check Process ID

Tenemos la función getmypid() que devolverá el id del proceso actual de scripts. ¿Hay algún tipo de función como

checkifpidexists() en php? Me refiero a una solución de script incorporada y no de lotes.

¿Y hay alguna manera de cambiar los scripts pid?

algunas aclaraciones:

Quiero comprobar si existe un PID para ver si el guión ya está en ejecución por lo que No corra de nuevo, trabajo cron falso si se quiere.

La razón por la que quería cambiar el pid es para poder establecer el script pid en algo realmente alto como 60000 y el código duro que valor para que este script solo pueda ejecutarse en ese pid para que solo 1 instancia funcione

EDITAR ----

para ayudar a cualquier persona con esta proplem, he creado esta clase:

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

} 

y usarlo de esta manera:

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

Respuesta

17

En Linux, debería mirar/proc.

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

En Windows que podría shell_exec() Tasklist.exe, y que encontraría un identificador de proceso de coincidencia:

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

Creo que lo que quiere hacer es mantener un archivo PID. En los daemons que he escrito, comprueban un archivo de configuración, buscan una instancia de un archivo pid, sacan el pid del archivo pid, comprueban si existe/proc/$ pid, y si no, eliminan el pid archivo.

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

Las ID de proceso son otorgadas por el sistema operativo y no se puede reservar una identificación de proceso. Escribirías a tu daemon para respetar el archivo pid.

+0

pcntl_fork() no cambiará los procesos actuales pid! La función pcntl_fork() crea un proceso hijo que difiere del proceso primario solo en su PID y PPID. Consulte la página de manual de la horquilla (2) de su sistema para obtener detalles específicos sobre cómo funciona la horquilla en su sistema. – ennuikiller

+0

hmm, estaba esperando una manera más cruzada de comprobar si existía un pid :( – Ozzy

+0

Con mi edición, mencioné que no creo que él quiera pcntl_fork(), ni tampoco tendría la opción de pid. –

1

No, no puede cambiar ningún proceso pid. El kernel lo asigna y forma parte de las estructuras de datos del kernel

0

Como han dicho otros, no puede cambiar la identificación del proceso: está asignada y totalmente gestionada por el kernel del sistema operativo. Además, no ha dicho si esto está basado en la línea de comandos o en el servidor web: si es el último, es posible que ni siquiera obtenga el pid de su script.

El manual page for getmypid() contiene algunos ejemplos de bloqueo "optimista". Utilizo la palabra optimisitc ya que PHP nunca se acercará a los gustos de una aplicación web asp.net donde tiene un verdadero entorno de subprocesos con clases compartidas/estáticas y, por lo tanto, de Singleton para usar/abusar. Básicamente tiene la opción de:

  • Tocando un "archivo de bloqueo" en el sistema de archivos en alguna parte. Su secuencia de comandos comprueba si ese archivo existe: si lo hace, finalice, de lo contrario, toque ese archivo y continúe con el proceso
  • Estableciendo un indicador basado en la base de datos para indicar que el script se está ejecutando.Como arriba, pero use una tabla/campo db para marcar un script como en ejecución.

Ambos dependen de que la secuencia de comandos termine correctamente (ya que el último paso sería eliminar el indicador de bloqueo de archivo/db). Si una secuencia de comandos falla por cualquier motivo (o la máquina misma), puede quedar un proceso de ordenación manual para eliminar la bandera. No hay una solución fácil para esto, pero una vía para explorar sería observar el sellado de fecha en la cerradura, con un enfoque arbitario "si es anterior a X, la última carrera debe haberse estrellado".

6

Una mejor manera de lograr esto sería usar un archivo pid o un archivo de bloqueo. Simplemente verifique la existencia del archivo pid, créelo según sea necesario y complételo con su pid en ejecució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; 
    } 
    } 
?> 

y utilizarlo como sigue:

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

No hay mucho de comprobación de errores aquí, pero una rápida muestra que esto funciona en mi sistema.

+0

Este es el método que utilizan muchos daemons * nix. – Jason

1

Para comprobar si existe un PID en una máquina Windows que utilizo:

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

Tenga en cuenta que $ outputB [0] contiene un PID mensajes que no se puede encontrar , si el pid en verdad no existe! Entonces para validar utilizo el segundo argumento.