Newsgroup: it.comp.lang.delphi
Titolo: Procedure ?!?

Ciao a tutti, ho un piccolo problemino, devo sviluppare un applicativo che
esegue contemporeanamente (diciamo 10) ping, su ip diversi. Ovviamente dovrà
restituirmi il ping o il timeout. Per fare questo uso il componente
TIdIcmpClient o TIDPing delle Indy. Ovviamente 10 sarà basilare, potrebbe
essere + o -, e mettere sulla form 15 TIdPing è brutto, così, li creo
runtime, assegnando a tutti, un determinato ip da pingare. Problema la
procedura Reply, mi tocca farne una per ogni tipo Ping ad ip diverso o cosa?
Pensavo ad un array di procedure, irrealizzabili credo e così ho pensato di
vedere chi era il sender del comando Reply del Ping, ma niente, nn so come
fare. Devo per forza fare una procedura per ogni Ping o c'è qualche modo più
rapido? Alcuni mi hanno consigliato i Thread, ma nno ho la più pallida idea
di come farlo. Qualche soluzione, suggerimento?
Grazie
Ciao

Se ho capito bene il problema e' quello di capire quale dei 10 componenti
TIdPing sta chiamando la procedura.
Per riconoscerlo puoi usare il campo Tag. E' un campo che hanno tutti i
componenti e che puoi usare come vuoi. Ad esempio puoi numerare i 10
componenti da 0 a 9 e poi nella procedura leggere TComponent(sender).tag per
vedere qual'e' quello che sta chiamando la procedura.
Oppure se ogni oggetto ha un campo "host" (l'host da pingare), puoi
riconoscerlo chiamando TIdPing(sender).host.
Ciao!

Caspita che tu ci creda o no, è quello che stavo pensando di fare, ora che
ho visto che è fattibile, proverò subito. Grazie dell'info.
Ps:- Mettere un record all'interno di un altro record, è una brutta cosa?
Esempio
Tipo1 = record
gjkdfg: string;
fiogj : Integer;
end;
Tipo2 = record
  fjg : Tipo1;
fdgfdgf: Integer;
......
......
......
end;

 ho visto che è fattibile, proverò subito.
Hai provato?
Da quello che ho capito vorresti fare una cosa del genere:
for I := *[TIDComponent1]* to *[TIDComponentN]* do
  *[TIDComponentI]*.Ping;
Hai considerato il fatto che procedendo in questo modo per ogni ping passa
"n" tempo che moltiplicato per "x" pings passa "n" per "x" tempo? Sei poi
consideriamo anche i timeout...... Ci va di mezzo anche un caffè! :)
In questo modo non pinghi proprio in contemporanea. Se devi pingare 15 hosts
e per ogni ping impieghi 1 sec. ti toccherà attendere 15 sec + eventuali
caffè. ;)
--
Acqua
-------------------------------------------------------
Download new version of PixExperts for Delphi 6/C++ Builder at
http://www.salexander.supereva.it/Pix_Exp171D6.zip

Azz, in realtà è vero, qualche altro modo per risolvere il problema?

threads
Bye
A

I threads forniscono uno strumento per eseguire più routine di codice
distinte simultaneamente.
L’oggetto TThread si trova nella unit Classes. Puoi notare che il metodo
TThread.Execute è astratto. Questo significa che la stessa classe
TThread è astratta, quindi non si potrà creare mai una sua istanza. Si
può solo creare  un’istanza di un discendente della classe TThread.
Il modo più semplice di creare un’istanza di un discendente di TThread è
quello di selezionare Thread Object dal dialogo New Items fornito
dall’opzione di menu File/New. Una volta che hai selezionato Thread
Object dalla finestra di dialogo New Items, viene mostrata una finestra
di dialogo nella quale puoi inserire il nome per il nuovo oggetto.
Delphi crea così una nuova unit che conterrà l’oggetto:
type
  TTestThread = class(TThread)
private
  { Private Declarations }
protected
  procedure Execute; override;
end;
Come puoi notare, per creare un discendente della classe TThread, il
solo metodo che si deve sovrascrivere è Execute. Qui dentro puoi
scrivere il tuo codice per pingare gli hosts.
Credo che la miglior soluzione sia quella di pingare tutti gli hosts
all’interno di un solo thread. Comunque non li pingheresti
contemporaneamente. Ma, almeno, non tieni “occupato” il thread
principale dell’applicazione.
 
Supponiamo che tieni la lista degli hosts in un oggetto TstringList.
Potresti scrivere qualcosa del genere:
var
  HostsList: TstringList;
  IdIcmpClient: TIdIcmpClient;
procedure TTestThread.Execute;
var
 I: Integer;
begin
  for I := 0 to Pred(HostsList.Count) do
  begin
    IdIcmpClient.Host := HostsList.Strings[I];
    IdIcmpClient.Ping;
  end;
end;
Il metodo Create della classe TThread è definito come segue:
constructor Create(CreateSuspended: Boolean);
Il singolo parametro Boolean passato al costruttore è chiamato
CreateSuspended, e indica se far partire il thread nello stato sospeso
(suspended). Se questo parametro è False allora il metodo Execute
dell’oggetto sarà automaticamente invocato in seguito a Create. Se il
parametro è True, affinché venga fatta effettivamente partire
l’esecuzione del thread bisognerà invocare, in qualche punto, il metodo
Resume di TThread. Questo causerà l’invocazione, in quel momento, del
metodo Execute. Si può impostare CreateSuspended a True, per esempio,
sei hai la necessita di impostare proprietà prima che questo venga fatto
partire. "Impostare proprietà dopo che un thread è già partito potrebbe
causare problemi".
Quindi, nel caso in cui vorresti che il metodo Execute venga invocato
immetiatamente dopo il Create dell'oggetto ti basta passare False come
parametro al costruttore.
var
  AThread: TTestThread;
begin
  AThread := TTestThread.Create(False);
end;
Attenzione. Un TThread è da considerarsi terminato quando il metodo
Execute termina la sua esecuzione. Viene rilasciata la memoria dello
stack del thread ed eliminata l’allocazione dell’oggetto thread stesso.
Sebbene questo accada automaticamente quando il processo termina, si
potrebbe voler rilasciare l’oggetto prima, cosicché l’applicazione non
incontri problemi di memoria durante l’esecuzione. Il modo più facile
per assicurarsi che l’oggetto TThread sia rilasciato è quello
d’impostare la sua proprietà
FreeOnTerminate a True.
È inoltre importante sapere che il metodo Execute del thread è
responsabile del controllo dello stato della proprietà Terminated per
determinare la necessità di eseguire un’uscita prematura. Per esempio,
nel momento in cui l'utente vuole uscire dall'applicazione, mica può
aspettare che finica il ciclo del thread secondario!
Quindi si potrebbe procedere nel seguente modo...
procedure TTestThread.Execute;
var
 I: Integer;
begin
  FreeOnTerminate := True;
  for I := 0 to Pred(HostsList.Count) do
  begin
    if Terminated then 
      Break;
    IdIcmpClient.Host := HostsList.Strings[I];
    IdIcmpClient.Ping;
  end;
end;
Antra cosa da prendere in considerazione....
Come posso da un thread secondario operare all'interno del thread
principale? Con la sincronizzazzione.
Ovviamente una volta che hai pingato devi poter fare qualcosa
all'interno del MainThread. Giusto? Visualizzare un messaggio, eseguire
un determinato compito.. etc.. etc..
Non puoi fare queste cose in maniera "diretta". Ricorda che mentre ti
fai i tuoi bei pings l'Applicazione "gira", l'utente potrebbe fare tutto
quello che gli pare in quel momento...
Quindi hai la necessita di "sincronizzare" le tue intenzioni, con
l'attuale comportamento dell'applicazione.
TThread fornisce un metodo chiamato Synchronize che tiene conto
dell’esecuzione di alcuni dei metodi propri del thread principale
dell’applicazione. Synchronize è definito nel seguente modo:
procedure Synchronize(Method: TThreadMethod);
Il suo parametro Method è di tipo TThreadMethod e quindi è un metodo
procedurale che non prende alcun parametro, ed è definito come segue:
type
  TThreadMethod = procedure of object;
Il metodo che si passa attraverso il parametro Method è quello che viene
poi eseguito dal thread principale dell’applicazione.
Ritornando all’esempio del TTestThread, supponiamo che vogliamo
visualizzare il risultato ottenuto da un ping  in un controllo label
sulla form principale. Si potrebbe far questo includendo in TTestThread
un metodo che operi le modifiche necessarie alla proprietà caption del
controllo label, invocandolo usando Synchronize.
type
  TTestThread = class(TThread)
private
  { Private Declarations }
  Host: string;
  HostPresente: Boolean;
protected
  procedure InformaUtente;
  procedure Execute; override;
end;
procedure TTestThread.InformaUtente;
var
  s: string;
begin
  if HostPresente then
    s := 'presente'
  else
    s := 'non presente';
  MainForm.Label1.Caption := 'Host ' + Host + ' ' + s;
end;
procedure TTestThread.Execute;
var
 I: Integer;
begin
  FreeOnTerminate := True;
  for I := 0 to Pred(HostsList.Count) do
  begin
    if Terminated then 
      Break;
    IdIcmpClient.Host := HostsList.Strings[I];
    IdIcmpClient.Ping;
  end;
end;
inontre dovresti associare all'evento OnReply del componente
IdIcmpClient un ulteriore metodo del thread secondario e all'interno di
questo metodo invocare il Synchronize(InformaUtente) dopo aver
valorizzato le dovute proprietà.
inizia a provare e facci sapere...
--
Acqua
-------------------------------------------------------
Download new version of PixExperts for Delphi 6/C++ 6 Builder at
http://www.salexander.supereva.it/Pix_Exp171D6.zip
-- 
Posted via Mailgate.ORG Server - 
http://www.Mailgate.ORG

Acqua,
[megacut]
complimenti, bel post!!!
Al prossimo nubbio che si lamenta perchè non ha ricevuto aiuto gli tiro 
dietro un manuale da mille pagine con copertina rigida ;O)
-- 
Ciao, Anto', [35, 143, AQ] 
MB C SC 220 CDI Magma Red
"Di sempre cio' che senti
 e fai cio' che pensi."
	G. Garcìa Màrquez

 principale dell’applicazione.
<SNIP>
Io userei n thread, simultanei se n<10-20 e mantenendone un pool attivi in 
caso contrario...
Ciao :-)
-- 
Andrea /\/\agni
ICQ# 174108000

 dietro un manuale da mille pagine con copertina rigida ;O)
Ancor meglio se č di Delphi! :D
Acqua
-------------------------------------------------------
Download new version of PixExperts for Delphi 6/C++ Builder at


 Ciao :-)
bye :o)
Acqua
-------------------------------------------------------
Download new version of PixExperts for Delphi 6/C++ Builder at
http://www.salexander.supereva.it/Pix_Exp171D6.zip
-- 
questo articolo e` stato inviato via web dal servizio gratuito 
http://www.newsland.it/news
 segnala gli abusi ad 
ab...@newsland.it

... senza parole, grazie, grazie grazie dell'info, veramente un'ottima
spiegazione, ho capito molte cose, grazie... Ora ho capito il funzionamento
dei thread, ed il loro uso...
Adesso mi sto mettendo all'opera, sempre con lo stesso programma, ma deve
fare qlc di più complesso, vedrò di risolvero con i thread. Un applicazione
che pinga vari host, max 5, e per ogni host apre 5 socket, in ocnitnua
connessione, verificando che nn ci siano problemi... Devo trovare una
soluzione per fare in modo che pingando, riesca anche a connettermi...
Infatti ora come ora usando un ciclo while per il ping
while not stop do
ping(host);
ed uno per i sock
while not stopsock do
open(host)
L'aaplicazione fa solo un lavoro... Riuscirò con i Thread a fare tutto
quello che mi serve?
Ps:- Grazie ancora dell'info sui Thread...