2011-12-09 21 views
6

Tengo un script perl que ejecuta una serie de scripts por lotes para pruebas de regresión. Quiero implementar un tiempo de espera en los scripts por lotes. Actualmente tengo el siguiente código.alarma perl con subproceso

my $pid = open CMD, "$cmd 2>&1 |"; 
    eval { 
       # setup the alarm 
       local $SIG{ALRM} = sub { die "alarm\n" }; 
       # alarm on the timeout 
       alarm $MAX_TIMEOUT; 
       log_output("setting alarm to $MAX_TIMEOUT\n"); 

       # run our exe 
       while(<CMD>) { 
         $$out_ref .= $_; 
       } 
       $timeRemaining = alarm 0; 
      }; 
      if ([email protected]) { 
        #catch the alarm, kill the executable 
      } 

El problema es que no importa lo que se propuso el tiempo de espera máximo para, la alarma se dispara nunca más. Intenté usar Perl :: Unsafe :: Signals, pero eso no ayudó.

¿Es esta la mejor manera de ejecutar los scripts por lotes si quiero poder capturar su salida? ¿Hay alguna otra manera de hacer lo mismo que me permita usar alarmas, o hay otro método además de alarmas para agotar el tiempo del programa?

He creado un script de prueba para confirmar que la alarma funciona con mi versión de Perl y Windows, pero no funciona cuando ejecuto un comando como este.

Estoy ejecutando esto con activeperl 5.10.1 en windows 7 x64.

Respuesta

4

Es difícil saber cuándo funcionarán alarm, cuando una llamada sistema y no ser interrumpido por un SIGALRM, cómo el mismo código podría comportarse de manera diferente en diferentes sistemas operativos, etc.

Si sus tiempos de trabajo afuera, quiere matar el subproceso que ha comenzado. Este es un buen caso de uso para la alarma del hombre pobre: ​​

my $pid = open CMD, "$cmd 2>&1 |"; 
my $time = $MAX_TIMEOUT; 

my $poor_mans_alarm = "sleep 1,kill(0,$pid)||exit for 1..$time;kill -9,$pid"; 
if (fork() == 0) { 
    exec($^X, "-e", $poor_mans_alarm); 
    die "Poor man's alarm failed to start"; # shouldn't get here 
} 
# on Windows, instead of fork+exec, you can say 
# system 1, qq[$^X -e "$poor_mans_alarm"] 


... 

carreras de alarma de los pobres en un proceso separado. Cada segundo, verifica si el proceso con el identificador $pid aún está activo. Si el proceso no está activo, el proceso de alarma se cierra. Si el proceso sigue vivo después de $time segundos, envía una señal de interrupción al proceso (utilicé 9 para hacerlo imposible de procesar y -9 para extraer todo el árbol de subprocesos, sus necesidades pueden variar).

(El exec puede que no sea necesario. Lo uso porque también uso este modismo para monitorear procesos que pueden sobrevivir al script de Perl que los lanzó. Como ese no sería el caso con este problema, podría omitir la llamada exec y dicen

if (fork() == 0) { 
    for (1..$time) { sleep 1; kill(0,$pid) || exit } 
    kill -9, $pid; 
    exit; 
} 

en su lugar.)

Cuestiones relacionadas