2016-05-17 2 views
1

Я просматриваю скрипт Perl, который использует waitpid($pid, 0), чтобы дождаться завершения текущего процесса. Но заявление print, написанное сразу после этого waitpid, печатает его до завершения процесса.Как ждать завершения процесса в Perl при запуске процесса не является дочерним процессом?

Я хочу знать, почему waitpid не ждет завершения процесса в первую очередь.

Кроме того, управление запущенным процессом осуществляется под другим модулем, а не частью этого скрипта perl. Доступно только pid и имя процесса. Я не могу ничего изменить в модуле, который вызывает этот процесс.

+0

Вы уверены, что '$ pid' - это то, что вы думаете? Что такое возвращаемое значение 'waitpid'? Он укажет, какой процесс завершен. – Schwern

+0

@Schwern - возвращаемое значение waitpid равно -1. Это означает, что такого дочернего процесса я не думаю. И я добавил ниже строк, чтобы проверить, что $ pid запущен или нет. my $ exists = kill 0, $ pid; print «Процесс запущен \ n", если ($ существует); И он печатает заявление – user3395103

+2

Вы не можете. Вы можете «подождать» только на дочернем процессе. См. 'Perldoc wait' (или' waitpid', это то же самое), первое предложение. Если вы хотите знать, когда завершается внешняя программа, вы должны делать совершенно разные вещи. – zdim

ответ

2

Примечание   Простой мысленный однострочный аппарат с kill 0, $pid находится в конце, прокомментирован.


Нам необходимо обнаружить завершение внешней программы, которая не была запущена этим скриптом. Вопрос спрашивает об использовании waitpid. Чтобы скопировать мой ранний комментарий:

Вы не можете. Вы можете ждать только дочернего процесса. См. perldoc wait (или waitpid, это то же самое), первое предложение.

wait и waitpid ждать сигналов, доставленных сценарий относительно судьбы своего ребенка (детей). Нет причин для сценария получать такие сигналы о процессах, которые он не запускал.


Мы знаем идентификатор процесса и его название.Его PID можно использовать для опроса для того, работает ли он. Использование pid само по себе не является полностью надежным, так как между нашими проверками процесс может завершиться, а случайному новому присваивается то же самое pid. Мы можем использовать название программы, чтобы укрепить это.

В системе Linux информация о процессе может быть получена путем использования (many) ps вариантов. В любом из этих возвращений полного вызова в программах

 
ps --no-headers -o cmd PID 
ps --no-headers -p PID -o cmd 

Возвращается строка может начинаться с путем интерпретатора (для сценария Perl, например), а затем полным именем программы. Версия ps -p PID -o comm= возвращает только имя программы, но я обнаружил, что она может сломать это слово на дефис (если есть), что приведет к неполному имени. Это может потребоваться настроить на некоторых системах, пожалуйста, проконсультируйтесь с вашим man ps. Если нет процесса с данным PID, мы ничего не получаем.

Затем мы можем проверить PID, и если найдено, проверьте, соответствует ли имя для этого PID программе. Название программы известно, и мы можем просто сделать это жестко. Тем не менее, он по-прежнему получается скриптом по мере его запуска, используя команду ps, чтобы избежать двусмысленностей. (Тогда это также в том же формате для последующего сравнения.) Это само проверяется на известное имя, так как нет гарантии, что PID во время выполнения скрипта действительно для ожидаемой программы.

use warnings; 
use strict; 

# For testing. Retrieve your PID as appropriate for real use  
my $ext_pid = $ARGV[0] || $$; 

my $cmd_get_name = "ps --no-headers -o cmd $ext_pid"; 

# For testing. Replace 'sleep' by your program name for real use 
my $known_prog_name = 'sleep'; 

# Get the name of the program with PID 
my $prog_name = qx($cmd_get_name); 

# Test against the known name, exit if there is a mismatch 
if ($prog_name !~ $known_prog_name) { 
    warn "Mismatch between:\n$prog_name\n$known_prog_name -- $!"; 
    exit; 
} 

my $name; 
while ($name = qx($cmd_get_name) and $name =~ /$prog_name/) 
{ 
    print "Sleeping 1 sec ... \n"; 
    sleep 1; 
} 
# regex above may need slight adjustment, depending on format of ps return 

Вывода команды, полученный через qx() выше (оператор кавычки) содержит символ новой строки. Если это окажется проблемой в сценарии, это может быть chomp -ed, что потребует небольшой корректировки. Оставшаяся лазейка заключается в том, что , что может быть закончена и перезагружена между проверками и с тем же PID.

Это будет испытана путем запуска в оболочке

 
sleep 30 & 
script.pl `ps aux | egrep '[s]leep'` 

egrep является grep -E. Выходной сигнал от `ps ...` содержит несколько слов. Они передаются в качестве аргументов командной строки для нашего скрипта, который использует первый как PID. Если есть проблема с этим, сначала выполните фильтрацию ps, а затем вручную введите PID в качестве входного аргумента скрипта. sleep из 30 секунд выше, чтобы дать достаточно времени, чтобы сделать все это в командной строке.

Код может быть упрощен путем сопоставления $name с жестким кодом $prog_name, если имя программы достаточно уникально, и оно не изменится. Твердое имя - это, использованный выше, но для проверки и генерирует предупреждение, если оно несовместимо. (Если мы полагаться на него только HARDCODED мы не можем выдавать предупреждения, если он не соответствует, так как это то часть работы кода.)


Если процесс принадлежит тому же пользователю, что и сценарий можно использовать kill 0, $pid как

while (kill 0, $ext_pid) { sleep 1 } 

Тогда вы должны либо сделать еще один вызов, чтобы проверить имя или удовольствоваться (маленький) возможность ошибки в том, что сам процесс $pid представляет.

Модуль Proc::ProcessTable может использоваться для всего этого. В системе Windows это был бы путь.

+0

да, это сработало для меня – user3395103

+0

@ user3395103 Рад, что это сработало. Оказалось, длинный пост, дайте мне знать, если есть какие-то вопросы или проблемы. – zdim

3

В waitpid documentation состоянии:

Уэйтса для конкретного дочернего процесса прекратить и возвращает идентификатор процесс умершего процесс, или -1, если нет такого процесса ребенка.

Быстрый тест:

my $pid = open my $fh,"-|","sleep 3"; 
print waitpid(28779,0); # Some other process 
print waitpid($pid,0); 

28779 другой процесс в настоящее время работает (взял случайный один из ps axu). Выход:

-1 
4088 

Вы не можете использовать waitpid ждать процесса, которые не являются потомком текущего процесса.

The kill command может проверить, если PID в настоящее время работает:

print kill(0,28779); 

Выход:

1 

Вы все еще необходимо опрашивать (цикл со сном) для ФИД исчезнуть. Также помните, что контролируемый процесс может выйти, и новый может повторно использовать один и тот же PID перед следующей проверкой (маловероятно, но возможно).