2015-10-24 4 views
2

Я пишу эмулятор в PERL для тестирования другой программы. Ниже код запускает цикл, который проверяет команды (initialize, exit, start_trace, stop_trace). Когда команда «start_trace» считывается, она разворачивает процесс, который просто выплескивает числа каждую секунду. Я хочу использовать «stop_trace», чтобы убить ребенка, но он также убивает родителя. Что мне не хватает?Perl kill child process также выходит из родительского?

use warnings; 
use strict; 

my $pid = undef; 

$| = 1; 

$SIG{TERM} = sub { 
    if ($pid == 0) { 
     print "Parent, not terminating\n"; 
    } else { 
     print "Child ($pid) terminating\n"; 
     exit(1); 
    } 
}; 


print "entering loop\n"; 
while (1) { 
    while (<>) { 
     my ($command, @args) = split(); 
     if ($command eq "exit") { 
      exit 1; 
     } 
     elsif ($command eq "initialize") { 
      print "s: ok\n"; 
     } 
     elsif ($command eq "start_trace") { 
      if (defined $pid) { 
       print "child already running\n"; 
      } else { 
       $pid = fork(); 
       if ($pid == -1) { 
        print "failed to fork\n"; 
        exit 1; 
       } 
       elsif ($pid == 0) { 
        print "Parent\n"; 
       } 
       else { 
        my $timestamp = 0; 
        while (1) { 
         for (my $i = 0; $i < 12; ++$i) { 
          printf "%.3f %.0f %.2f %.1f\n", 
           ++$timestamp, 
           0, 
           0, 
           100 * rand() 
          ; 
         } 
         sleep(1); 
        } 
       } 
      } 
     } 
     elsif ($command eq "stop_trace") { 
      kill "TERM", $pid; 
      #waitpid($pid, 0); 
      $pid = undef; 
     } 
     else { 
      printf "s: unknown command $command\n"; 
     } 
    } 
} 

выхода (не стандартный ввод & стандартных вывода все смешаны вместе, но я печатаю "stop_trace")

stop85.000 0 0.00 66.6 
86.000 0 0.00 43.3 
87.000 0 0.00 82.3 
88.000 0 0.00 62.8 
89.000 0 0.00 43.5 
90.000 0 0.00 50.0 
91.000 0 0.00 8.8 
92.000 0 0.00 89.3 
93.000 0 0.00 61.4 
94.000 0 0.00 92.4 
95.000 0 0.00 46.6 
96.000 0 0.00 53.9 
_trace 
Child (26644) terminating 
Parent, not terminating 
% 

Но оба они вышли! Зачем?

ответ

4

Я думаю, что есть логическая ошибка здесь - когда вы fork(), что происходит два бита код ветви - и только разницы в этой точке, что дочерний процесс имеет код возврата от fork() нуля, и он parent имеет код возврата $pid.

Он возвращает дочерний pid родительскому процессу, 0 - дочернему процессу, или undef, если вилка неудачна.

Так что я думаю, что ваша логика назад, когда вы проверяете:

elsif ($pid == 0) { 
    print "Parent\n"; 
} 

Это на самом деле ваш родитель который ввод, что в то время как цикл, и ваш дочерний процесс, который по-прежнему читает со стандартного ввода на время цикла.

И я думаю, именно поэтому у вас возникли проблемы - потому что ребенок набирает stop_trace и выдачи kill "TERM", 0, а не ребенок Pid он должен убивать.

Я не совсем уверен, что должно быть должно происходить, когда вы убиваете pid 0. Но по внешнему виду - это сигнализирует обоим процессам в любом случае.

И у вас есть такая же логическая ошибка в вашем обработчике сигнала - ваш родитель убит, потому что он имеет $pid, установленный в 0. Я не уверен на 100%, почему это приводит к выходу вашего ребенка, хотя вы уверены, что это действительно так, и вы не накапливаете устаревшие процессы, сидящие в while(1) с закрытым STDIN?

Прост достаточно, чтобы проверить, хотя - придерживаться print "$$: killing child with pid $pid\n"; в том, что stop_trace отрасли.

Oh - и fork in perl возвращает undef не -1 если это не удалось.

+0

О, боже, вы правы. Я изменил == 0 на! = 0 в обработчике и в цикле, и все в порядке. Спасибо. Должен ли я удалять этот пост? – PeterT

+0

Я не вижу в этом необходимости - это разумный вопрос и может быть полезен будущим читателям. – Sobrique

Смежные вопросы