Newsgroup: it.comp.lang.delphi
Titolo: Problema impostazione debugger su procedure di thread

Salve amici!
Mi stň cimentando (come suggeritomi in altro post) nello sviluppare un 
programma che usa i thread.
Ho definito un thread cosě:
type TThreadListener=class (TThread)
 Sorgente: TApdComPort;
 procedure InizializzaCom(porta:string);
 procedure Accendi();
 procedure Execute; override;
 procedure SorgenteTriggerAvail(CP: TObject; Count: Word);
end;
Dove "Sorgente" č un componente non visuale che "ascolta" la seriale e se ci 
sono dati scatena l'evento "TriggerAvail", quindi ho definito
la procedura
procedure TThreadListener.SorgenteTriggerAvail(CP: TObject; Count: Word);
var
S : string;
I : Word;
begin
  for I := 1 to Count do
   S := S + Sorgente.GetChar;
   showmessage(s);
end;
Le procedure Accendi,etc...funzionano perfettamente.
Ma non capisco perchč se metto un breakpoint sullo "showmessage" questo 
viene ignorato completamente (avete presente quando mettete per sbaglio un 
breakpoint su un commento e viene la riga verde? a me capita uguale!).

Mi rispondo da solo...
Non avevo fatto l'associazione:
Sorgente.OnTriggerAvail:=SorgenteTriggerAvail;
nella create dell'oggetto :)

Continuo su questo post....
Guardate qua:
procedure TThreadListener.SorgenteTriggerAvail(CP: TObject; Count: Word);
var
S : string;
I : Word;
begin
  for I := 1 to Count do
   S := S + Sorgente.GetChar;
Ricevuta:=S;
Synchronize(AggiornaStringa);  //questo dovrebbe evitare tutti i problemi di 
accesso alle variabili
end;
procedure TThreadListener.AggiornaStringa();
begin
FastPcr1K.StringaRicevuta:=Ricevuta;
end;
Perchè quando faccio "FastPcr1K.StringaRicevuta:=Ricevuta;" mi dà access 
violation??????
Mettendo un BP su quella riga, FastPcr1K (che è la form principale del mio 
progetto!) è nil! Strano o mi sono "bevuto il cervello"???

progetto!) è nil! Strano o mi sono "bevuto il cervello"???
Sei sicuro di non istanziare il thread *prima* che la main form venga
creata ?  

 creata ?
Sicurissimo, dato che il thread lo creo premendo su un tasto della form 
principale

 creata ?
Per la variabileinaccessibile, ho risolto spostandola nella variabili 
generali; ma per quanto riguarda gli oggetti visuali della form come devo 
comportarmi? Ottengo sempre "access violation" quando provo a fare roba tipo 
FastPcr1K.edit1.text:='ciao' in quanto risulta sempre che FastPcr1K è "nil".
Qualche idea?

 ha scritto nel messaggio 
news:4502713d$0$35083$4faf...@reader4.news.tin.it...


 Giorgio
Ehm...mica ho capito sai?
Il problema è (come avrai letto) che ottengo sempre access violation.
La unit della form crea il therad quindi la uni è fatta così (ho tagliato 
molta roba,come la creazione del thread,etc...):
unit fastpcr1kfrm;
interface
uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls, Buttons, JvExControls, JvComponent, JvSwitch,
  JvInstallLabel, JvxSlider, JvSimScope,inifiles,SyncObjs,
  JvSimIndicator, Grids, DBGrids, DB, ADODB, OoMisc, AdPort, ExtCtrls,
  AdPacket, JvSegmentedLEDDisplay, JvLED, JvFormAnimation, JvProgressBar,
  JvDBGridExport, Spin, VrControls, VrButtons, VrUpDown, VrWheel,
  JvWaitingGradient, JvGIF, VrMatrix, VrLcd, DBCtrls,EXECryptor, XPMan;
type TThreadListener=class (TThread)    //questo è il thread
 Sorgente: TApdComPort;
 Ricevuta:string;
 procedure InizializzaCom(porta:string);
 procedure Accendi();
 procedure Execute; override;
 procedure AggiornaStringa();
 procedure SorgenteTriggerAvail(CP: TObject; Count: Word);
end;
type                                            //questa è la form "visuale"
  TFastPcr1K = class(TForm)
    btClose: TBitBtn;
    Volume: TJvxSlider;
    ADOTblGenerale: TADOTable;
    DataSource: TDataSource;
    cbCOM: TComboBox;
    Label1: TLabel;
.....
.....
private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  StringaRicevuta:string;
  FastPcr1K: TFastPcr1K;
  Listen:TThreadListener;
  Worker:TThreadWorker;
implementation
uses Main;
.............
............
procedure TThreadListener.SorgenteTriggerAvail(CP: TObject; Count: Word);
var
S : string;
I : Word;
begin
  for I := 1 to Count do
   S := S + Sorgente.GetChar;
Ricevuta:=S;
Synchronize(AggiornaStringa);
end;
procedure TThreadListener.AggiornaStringa();
begin
StringaRicevuta:=Ricevuta;
FastPcr1K.Radio1.Enabled:=True;                //qui ottengo access 
violation! (FastPcr1K è nil!)
FastPcr1K.JVLed.Status:=False;                //idem!
end;

 ha scritto nel messaggio 
news:45029cc5$0$47969$4faf...@reader3.news.tin.it...


 Giorgio
Proprio non me lo spiego :(    sicuramente sarà una cavolata la 
soluzione...speriamo nell'intuito di qualcuno :)
Grazie dell'interessamento 

strano quanto ottieni in debug.
QUOTA CORRETTAMENTE !

[...]TThreadListener
Dove lo crei ?

 Dove lo crei ?
Lo creo quando premo su un tasto della form.

(c'è solo begin end;
Che vuol dire ? ... quindi il tuo thread non fa nulla ?

"Andrea Laforgia" <a.laf...@andrealaforgia.it.invalid> ha scritto nel 
messaggio news:2ed5g2pi0vbjilokr...@4ax.com...

1) Non fà nulla nella execute
2) Nel thread ho definito anche il famoso oggetto che ascolta i dati 
provenienti dalla seriale.
3) Quando attivo il thread, subito dopo attivo il componente che "ascolta" e 
si comporta benissimo (l'evento si scatena e viene processato benissimo).
4) Il problema stà quando devo modificare lo stato dei componenti della form 
principale (dal thread ovviamente), se faccio un debug, l'handle della form 
principale è nil :(

si comporta benissimo (l'evento si scatena e viene processato benissimo).
Quello che stai facendo non ha senso.  Il tuo thread deve mettersi in
ascolto ciclico di messaggi con l'API GetMessage(), l'oggetto che
ascolta dalla seriale avrà per evento di ricezione un metodo del
thread, che si limiterà a mandare un messaggio al thread stesso
segnalando la presenza di dati.  Una volta ricevuto il messaggio, il
thread deciderà se rimbalzare ancora un messaggio alla form principale
con i dati (cosa che io ti consiglio di fare), oppure invocare un
metodo di aggiornamento con Synchronize.  Se l'aggiornamento dei dati
a video è ritardabile di qualche millisecondo, allora è sicuramente
MOLTO meglio seguire la strada dei messaggi per comunicare tra thread
e form principale.

 e form principale.
Non ho capito....quello che voglio fare è (come mi hai consigliato nel post 
di 2 settimane fà circa) questo:
"thread (listener) che ascolta dalla seriale con il componente incluso" -> 
invia i dati ricevuti ad un "secondo thread (worker) che elabora i dati ed 
aggiorna i componenti visuali della form".
Stò procedendo per passi, prima di creare il secondo thread voglio vedere se 
riesco almeno ad aggiornare una label della form principale,o cmq un 
componente visuale della stessa; quello che mi "blocca" ad andare avanti è 
che l'handle della form principale (dal thread) risulta "nil".
Potresti spiegarmi meglio (considera che mi stò avvicinando ai thread) come 
ti comporteresti tu?
Grazie dell'attenzione!

che l'handle della form principale (dal thread) risulta "nil".
Quello che ti blocca è che non hai compreso come utilizzare i thread
in Delphi.
1) ogni thread deve avere una coda di messaggi e la creazione della
coda di messaggi di ciascun thread deve essere forzata dall'esterno
con una PostThreadMessage di un WM_NULL fino a che questa funzione non
risponde True;  In generale è bene creare una classe "controller", che
venga istanziata dal thread primario e wrappi le operazioni di
controllo del thread (che avverranno sempre tramite messaggi).
2) ogni thread deve attendere per l'arrivo di messaggi, nel suo flusso
principale e rispondere a ciascuno di essi con una funzione specifica;
Un esempio banale è il seguente (scritto al volo):
const
  CM_THREAD_DO_SOMETHING = WM_USER+100;
  CM_THREAD_TERMINATE    = WM_USER+101;
type
  TMyThread = class(TThread)
  protected
    procedure Execute; override;
  end;
  TMyThreadController = class
  private
    FThread: TMyThread;
  public
    constructor Create;
    destructor Destroy; override;
    procedure DoSomething;
  end;
....
{ TMyThread }
procedure TMyThread.Execute;
var
  Msg: tagMSG;
begin
  inherited;
  while (not Terminated) and
        (GetMessage(Msg, 0, 0, 0, 0)) do
  begin
    case Msg.message of
      CM_THREAD_TERMINATE: Terminate;
      CM_THREAD_DO_SOMETHING: begin
        // ...
      end;
    end;
  end;
end;
{ TMyThreadController }
constructor TMyThreadController.Create;
begin
  FThread := TMyThread.Create(False);
  FThread.FreeOnTerminate := True;
end;
procedure TMyThreadController.DoSomething;
begin
  if Assigned(FThread) then
    PostThreadMessage(FThread.Id, CM_THREAD_DOSOMETHING, 0, 0);
end;
destructor TMyThreadController.Destroy;
begin
  if Assigned(FThread) then
  begin
    PostThreadMessage(FThread.Id, CM_THREAD_TERMINATE, 0, 0);
    FThread.WaitFor;
  end;
  inherited;
end;

end;
n.b.: dove ho scritto FThread.Id in realtà è FThread.ThreadId

Ok...mò mi leggo ben bene quello che hai scritto e mi rifaccio sentire.
 Thanks!