Newsgroup: it.comp.lang.perl
Titolo: eseguire una sub ogni tot minuti

Come faccio ad eseguire una funzione ogni tot minuti?
[code]
$socket->listen();
while ( $client = $socket->accept() )
{
    while ( $str = <$client> ) { syswrite $client, uc($str) . "\r\n"; }
 
    # esegui funzione() ogni 10 minuti...
}
sub funzione() { return }
[/code]
non è che devo eseguirla per forza dentro al ciclo while...ma di 
instinto mi è venuta di mettere la chiamata la dentro...

 wrote:

non si può fare in perl puro? 
io eseguo un file .pl che all'interno ha: 
code:
------------------------------------------------------------------------
while(1)
{
    # esegui sub() ogni 10 min....
}
------------------------------------------------------------------------
il file gira in eterno...e ogni 10 min esegue una sub()...

 il file gira in eterno...e ogni 10 min esegue una sub()...
A me sembra più sensato mettere questa "sub" in un file .pl e farlo eseguire 
ogni 10 minuti da Cron (risparmiando risorse e potendo usufruire di un log 
già fatto).
A meno che non debba essere fatto su un sistema senza Cron.

 wrote:

no,lo devo fare dentro al file...perchè quando il file non è più in 
esecuzione non mi interessa più la sub...
ti posso chiedere come traduci in millisecondi 10 e 30 minuti?

 ti posso chiedere come traduci in millisecondi 10 e 30 minuti?
Quello che chiedi può essere fatto con il while (1) come hai detto, 
dentro al quale c'è la chiamata alla sub e una chiamata a sleep:
perldoc -f sleep
    sleep EXPR
    sleep   Causes the script to sleep for EXPR seconds
Per granularità più fini del secondo:
http://www.perl.it/documenti/faq/view.html?pag=8&faq=16
Ovviamente se devi stare fermo 10 min: 10min*60s=600 secondi.
Su 600 secondi quanti millesimi di secondo ho? Se 1 secondo=1000 
millesimi, allora 600 secondi sono 600.000 millesimi.

 instinto mi č venuta di mettere la chiamata la dentro...
Gia' ti hanno detto di mettere sleep(10); dentro al ciclo while()
e quindi io mi permetto di divagare un po:
sub temporizzata
{
  $dataora = gmtime(time());
  print "\n",$dataora,"\n";
  $SIG{'ALRM'} = \&temporizzata;
  alarm(10);
}
$SIG{'ALRM'} = \&temporizzata;
alarm(10);
$inputstring = <STDIN>;
# programma bloccato su una operazione di input.
# aspettare a dare input per vedere le chiamate
# all' handler di SIGALRM, che si reinstalla e
# setta nuovamente alarm(10) (10 secondi).
cosi' il programma puo fare altro mentre aspetta 10 secondi.
in questo caso si ferma su un input, ma puo' anche star processando
qualcosa.
il signalhandler come vedi viene reinstallato
ciao.
Roberto.
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

 Roberto.
cerco di spiegarti quello che intendo...
ho una connessione socket che si mette in listen in attesa di una 
chiamata:
while ( $client = $socket->accept() )
{
   # attendo connessione...
 
   # intanto durante l'attesa ogni 10 min eseguo una funzione...
}
se metto sleep 10 lo script non mi si mette in pausa per 10 min? (te lo 
chiedo)
avrei potuto fare 2 threads: 1) che si mette in ascolto 2) che ogno 10 
min mi esegue una funzione,
ma la mia piattaforma non me lo permette!
spero che tu abbia capito il concetto
.
.
.
tu dici di mettere alarm(10) all interno del while?
while {
$SIG{'ALRM'} = \&temporizzata;
alarm(10);
}
oppure all'esterno?
grazie!

 grazie!
all' esterno, prima del while(). per il tuo caso specifico non so'
dirti se e' la soluzione migliore, ti spiego solo questa tecnica:
Sitratta di gestire un evento in modo asincrono al flusso del programma,
quindo scrivi il programma come se non dovesse eseguire quella funzione,
poi definisci la funzione, ne metti il reference come handler di
SIGALRM (appunto $SIG{'ALRM'} = &temporizzata;) e quindo registri nel
sistema un evente, cioe' chiedi che il sistema ti mandi tra x secondi
un SIGALRM.
La parodia e' quelle di lavorare con una sveglia e un pezzo di carta e
penna:
immagina di fare un lavoro d' ufficio per 8 ore al giorno ad una scrivania
con attivita' da impiegato, ma con una serie di attivita' fisse comandate
ad orari precisi durante il giorno. (esempio telefonate di ispezione,
accendere/spegnere riscaldamenti, cambiare nastri di backup ....)
1) Metti su carta le attivita' ordinate per ora
2) setti la sveglia alla prima attivita'...
3) ti metti a fare lavoro di routune (pratiche, CHAT, Solitario,..)
4) suona la sveglia. la fermi, depenni l' attivita', la esegui,
   riarmi la sveglia alla prossima attivita' in lista.
5) torni al punto 3)
quindi quando l' handler (la sub temporizza) si riarma, anziche' settare
alarm(10) potrebbe fare un lookup ad una tabella di alarms.
es:
if ($i < scalar(@attivita)) {alarms($attivita[$i++]);}
else {$SIG{'ALRM'} = 'DEFAULT'; # handlersi sistema}
o se preferisci rotativo:
alarms($attivita[$i++ % scalar(@attivita)]);
ATTENZIONE!!!! Alcune syscall per socket sono state progettate
per sbloccarsi alla ricezione di un signal, mi sembra proprio
accept() e forse anche select(). Non e' escluso che dovrai
eseguire dei controlli aggiuntivi per verivicare se l' uscita
da accept corrisponde a una connessione entrante o alla ricez
di un SIGALRM.
Inoltre se usi un server concorrente (che sempre consiglio)
lato figlio il SIGALRM va subito rimesso a 'DEFAULT'.
Hai provato se alarm() sul tuo sys funziona? E' UNIX/LINUX o win?
Ciao.


 di un SIGALRM.
Confermo! Su Linux e' proprio cosi' (Tu cosa usi?)
questo e' l' esempio modificato dell' echoserver che ho mandato
qualche giorno fa. Non si "daemonizza" piu' perche' il processo
padre scrive su STDOUT la testimonianza dell' avvenuta esecuzione
di &temporizza():
--------- echoserver 02 --------------
#!/usr/bin/perl
use Socket;
use strict; # e' un pragma per la sicurezza. vedi perldoc -U -m strict
            # mi costringe a dichiarare le variabili com my.
my $proto = getprotobyname('tcp');
my $port = 6362;
socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die "err in syscall
socket()\n";
setsockopt(SOCK, SOL_SOCKET, SO_REUSEADDR, pack("l", 1)) or
  die "err in syscall setsockopt()\n";
bind(SOCK, sockaddr_in($port, INADDR_ANY)) or die "err in syscall
bind()\n";
listen(SOCK, SOMAXCONN) or die "err in syscall listen()\n";
$SIG{CHLD} = 'IGNORE'; # Riceve SIGCHLD ed evita popolamento di zombies
my $dataora;
sub temporizzata # stampa a console su processo padre data/ora ogni 10 sec.
{
$dataora = gmtime(time());
print "\n",$dataora,"\n";
$SIG{'ALRM'} = \&temporizzata;
alarm(10);
}
$SIG{'ALRM'} = \&temporizzata;
alarm(10);
# ATTENZIONE! la seguente funzione non e' portabile! pathname Linux.
# copiata da perldoc -U perlipc
use POSIX 'setsid';
sub daemonize
{
  chdir '/'                    or die "err chdir()\n";
  open STDIN, '</dev/null'     or die "err open()\n";
  open STDOUT, '>/dev/null'    or die "err open()\n";
  defined(my $pid = fork())    or die "err fork()\n";
  if ($pid)  { exit(); }
  no strict;
  setsid()                     or die "err setsid()\n";
  use strict;
  open STDERR, '>&STDOUT'      or die "err open()\n";
}
print "Echo Server in esecuzione. Porta $port\n";
# daemonize(); # non daemonizziamo! ci serve STDOUT.
while ((my $newsocket = accept(REMOTE,SOCK)) , 1) # 1 ci vuole per rendere
                                                  # sempre true espressione
{
  if ($newsocket)
 
  {
    print "\nnuovo socket\n";
 
    if (fork()) { close REMOTE; } # se sono processo padre chiudo
                      # nuovo socket e mi rimetto in accept()
    else
      { # se sono processo figlio chiudo sochet in LISTEN e comunico
        # con client tramite nuovo socket.
        close SOCK;
        $SIG{PIPE} = 'IGNORE';
        $SIG{'ALRM'} = 'DEFAULT';
        my ($remoteport, $remoreaddr) = sockaddr_in($newsocket);
        while (my $str = <REMOTE>)
          { syswrite REMOTE, uc($str); }
        exit 0;
      }
  }
  else { print "\nuscito da accept() con ricez. SIGNAL\n"; }
}
----------- fine echoserver 02 ---------
Ma sul tuo sys riesci a collaudare i miei esempi? Funzionano su Linux, ma
sono interessato a sapere se queste porzioni di codice siano portabili.


 Come faccio ad eseguire una funzione ogni tot minuti?
Usa IO::Select ed evita di bloccare l'esecuzione in 'accept'. 
Esempietto.
  use IO::Select;
  # [...]
  $socket->listen();
  my $s = IO::Select->new();
  $s->add($socket);
  my $last_triggered = time();
  while (1)
  {
      my $timeout = ( $last_triggered + 10 ) - time();
      my @handles = $s->can_read( $timeout > 0 $timeout : 0 );  
      if( @handles )
      {
        my $client = $socket->accept() ;
        while ( my $str = <$client> ) { 
              syswrite $client, uc($str) . "\r\n"; }
      }
      else
      {
            $last_triggered = time();
            print "Trascorsi 10 secondi...\n";
      }
 
  }
 
Nota che in questo modo non riesci comunque a garantire l'esecuzione ogni 
10 secondi *mentre* č attiva una connessione. Puoi riuscirci, se inserisci 
nella 'select' anche la gestione (lettura/scrittura) della connessione. 
(Per inciso, usando la 'select' puoi anche riuscire a gestire piů 
connessioni simultaneamente senza usare thread o processi aggiuntivi, a 
condizione che ciascuna connessione non richieda lunghe elaborazioni.)
Max

 
Sono su MacOS9 con MacPerl5 (fork non implementata,pochi moduli 
installati)
Il giorno che installo MacOSX (unix,perl,apache,mysql,php etc...) faccio 
festa! (ma solo quando avrò un Mac tutto per me)
btw: non ho mai usato un terminale (tipo unix) in vita mia...