A Donde se Retorna Después de la Ejecución del Manejador de una Señal

En la mayoría de los casos, con la llegada de la señal y después de la ejecución del manejador se restaura la ejecución de la subrutina interrumpida exactamente donde se dejó.

Una excepción a esta regla es la función sleep la cual suspende el programa por el número de segundos indicado como argumento. Si una señal interrumpe al proceso que está ejecutando sleep la función sleep retornará antes del número de segundos que se le hubiera indicado. Esta caracteristica es muy útil para hacer que un proceso sea desplanificado por un tiempo ilimitado hasta que ocurra un determinado suceso.

Otra excepción es la función select la cual puede ser utilizada para esperar a que uno de un conjunto de manejadores de fichero este listo para E/S. La función admite un umbral de tiempo. Si el umbral se sobrepasa sin que ningún manejador esté listo la función select termina.

De hecho en programas antiguos (o escritos usando un estilo obsoleto) es común ver el uso de select para emular un sleep con un número fraccional de segundos:

                   select(undef, undef, undef, 0.25);
En vez de esto es mejor usar las funciones usleep y nanosleep del módulo Time::HiRes.

Ejercicio 3.4.2   Considere el siguiente fragmento de la versión 0.7.5 de Parallel::ForkManager (repase la sección 3.10 en la que se introdujo el módulo):
sub start { my ($s,$identification)=@_;
  die "Cannot start another process while you are in the child process"
    if $s->{in_child};
  while ($s->{max_proc} && ( keys %{ $s->{processes} } ) >= $s->{max_proc}) {
    $s->on_wait;
    $s->wait_one_child(defined $s->{on_wait_period} ? &WNOHANG : undef);
  };
  $s->wait_children;
  if ($s->{max_proc}) {
    my $pid=fork();
    die "Cannot fork: $!" if !defined $pid;
    if ($pid) {
      $s->{processes}->{$pid}=$identification;
      $s->on_start($pid,$identification);
    } else {
      $s->{in_child}=1 if !$pid;
    }
    return $pid;
  } else {
    $s->{processes}->{$$}=$identification;
    $s->on_start($$,$identification);
    return 0; # Simulating the child which returns 0
  }
}

.....

run_on_wait { my ($s,$code, $period)=@_;
  $s->{on_wait}=$code;
  $s->{on_wait_period} = $period;
}

sub on_wait { my ($s)=@_;
  if(ref($s->{on_wait}) eq 'CODE') {
    $s->{on_wait}->();
    if (defined $s->{on_wait_period}) {
        local $SIG{CHLD} = sub { } if ! defined $SIG{CHLD};
        select undef, undef, undef, $s->{on_wait_period}
    };
  };
};

sub wait_children { my ($s)=@_;
  return if !keys %{$s->{processes}};
  my $kid;
  do {
    $kid = $s->wait_one_child(&WNOHANG);
  } while $kid > 0 || $kid < -1; # AS 5.6/Win32 returns negative PIDs
};
Cuando el periodo utilizado en el callback asociado con on_wait es grande (práctica 3.11) el programa que usa el módulo parece tardar en exceso. ¿Sabría explicar la causa de ese fallo?

Casiano Rodríguez León
Licencia de Creative Commons
Programación Distribuida y Mejora del Rendimiento
por Casiano Rodríguez León is licensed under a Creative Commons Reconocimiento 3.0 Unported License.

Permissions beyond the scope of this license may be available at http://campusvirtual.ull.es/ocw/course/view.php?id=44.
2012-06-19