PHP Check ID процесса - PullRequest
       7

PHP Check ID процесса

8 голосов
/ 01 ноября 2009

Это то, что я удивляюсь некоторое время и решил спросить об этом.

У нас есть функция getmypid (), которая будет возвращать текущий идентификатор процесса скриптов. Есть ли какая-то функция, такая как

checkifpidexists () в php? Я имею в виду встроенное, а не какое-то пакетное решение.

А есть ли способ изменить pid скрипта?

Некоторые уточнения:

Я хочу проверить, существует ли pid, чтобы убедиться, что скрипт уже запущен, поэтому он больше не запускается, если хотите, запустите faux cron.

Причина, по которой я хотел изменить pid, заключается в том, что я могу установить pid сценария на очень высокое значение, например 60000 и жесткий код, значение которого позволяет выполнять этот сценарий только на этом pid, поэтому будет выполняться только 1 его экземпляр

EDIT ----

Чтобы помочь кому-либо еще с этой проблемой, я создал этот класс:

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

Ответы [ 6 ]

17 голосов
/ 01 ноября 2009

В Linux вы можете посмотреть на /proc.

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

В Windows вы можете использовать shell_exec () tasklist.exe, и при этом будет найден соответствующий идентификатор процесса:

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

Идентификаторы процессов предоставляются ОС, и нельзя зарезервировать идентификатор процесса. Вы бы написали своему демону, чтобы он уважал файл pid.

6 голосов
/ 01 ноября 2009

Лучший способ сделать это - использовать 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";
  }
?>

Здесь нет особой проверки ошибок, но быстрый запуск показывает, что это работает в моей системе.

1 голос
/ 16 августа 2017

Для проверки наличия 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 действительно не существует! Поэтому для проверки я использую второй аргумент.

EDIT:

Чтобы расширить это, можно также динамически создавать сценарии в пределах окон в фоновом режиме, используя powershell, например:

    // this function builds an argument list to parse into the newly spawned script. 
    // which can be accessed through the superglobal  global $argv;
    function buildArgList( array $arguments){
     return ' '. implode(' ', $arguments) .' ';
    }

    $arguments = buildArgList(['argument1','argument2','argument3']);
    $windowstyle = 'normal'; // or you can use hidden to hide the CLI

    pclose(popen("powershell start-process -FilePath '" . PHP_BINARY . "' -ArgumentList '-f\"" . $file . " " . $arguments . "\"' -WindowStyle " . $windowstyle,"r"));   

Сценарий, который вы создали, может затем использовать: cli_set_process_title установить для заголовка этого процесса какой-то уникальный хеш.

внутри родительского объекта, породившего дочерний процесс, вы можете использовать следующий код, чтобы найти этот процесс в списке задач, используя его заголовок окна для поиска уникального хэша.

exec('TASKLIST /NH /FO "CSV" /FI "windowtitle eq ' . escapeshellarg($uniquehash) . '"', $output );

В сочетании с базой данных вы можете создать рабочий перманент общение между различными PHP-скриптами.

1 голос
/ 01 ноября 2009

Нет, вы не можете изменить процесс pid. Он назначается ядром и является частью структуры данных ядра

0 голосов
/ 01 ноября 2009

Не забывайте также, что вы можете получать доступ к командам оболочки через backticks (`), что даст вам доступ к стандартным инструментам * nix для работы с pids.

источник: http://www.php.net/manual/en/language.operators.execution.php

0 голосов
/ 01 ноября 2009

Как уже говорили другие, вы не можете изменить идентификатор процесса - он назначается и полностью управляется ядром ОС. Кроме того, вы не сказали, является ли это командной строкой или веб-сервером: если это последнее, вы, возможно, даже не получите pid своего скрипта.

Страница руководства для getmypid () содержит несколько примеров «оптимистической» блокировки. Я использую слово optimisitc, так как PHP никогда не будет похож на веб-приложение asp.net, где у вас есть настоящая многопоточная среда с общими / статическими классами и, следовательно, синглтонами для использования / злоупотребления. В основном у вас есть возможность:

  • Прикосновение к «файлу блокировки» в файловой системе. Затем ваш скрипт проверяет, существует ли этот файл: если он существует, завершите его, в противном случае коснитесь этого файла и продолжите обработку
  • Установка флага на основе базы данных, чтобы сказать, что скрипт запущен. Как и выше, но используйте таблицу / поле БД, чтобы пометить скрипт как работающий.

Оба они полагаются на корректное завершение скрипта (последним шагом будет удаление флага блокировки файла / db). Если по какой-либо причине происходит сбой скрипта (или самой машины), вы можете оставить ручную процедуру очистки, чтобы убрать флаг. Простого решения для этого не существует, но один из путей, который следует изучить, состоит в том, чтобы взглянуть на отметку даты с блокировкой с произвольным подходом «если он старше X, последний запуск должен был потерпеть крах».

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...