Italian community of Lazarus and Free Pascal

Programmazione => Generale => Topic aperto da: Diego1981 - Febbraio 13, 2017, 08:36:02 am

Titolo: Passare dati a un nuovo thread
Inserito da: Diego1981 - Febbraio 13, 2017, 08:36:02 am
Ciao Ragazzi
avevo una curiosità che non trova risposta  ;D
Creo un nuovo thread, nel costruttore assegno una classe da passare al thread
Come mai la classe nel thread(osservando il debug) perde tutti i dati quando la classe nel tread principale viene eliminata? (almeno penso)
Sto lavorando con il componente http server indy

aggiungo giusto 2 righe di codice
nella form principale
procedure TFR_Principale.HTTPServerCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
SesThrd:=Tusessionthrd.Create(False,ARequestInfo,AResponseInfo,AContext);
end;

nel thread
constructor Tusessionthrd.Create(CreateSuspended: Boolean;
  RequestInfo: TIdHTTPRequestInfo; ResponseInfo: TIdHTTPResponseInfo;
  Acontext: TIdContext);
begin
  inherited Create(CreateSuspended);
  ARequestInfo:=TIdHTTPRequestInfo.Create;
  ARequestInfo:=RequestInfo;//provo in questo modo
// ARequestInfo.Assign(RequestInfo);//ho provato anche cosi
.....
....
end;

Quando il Thread passa alla procedura execute nel debug la mia classe Arequestinfo perde tutti i dati, si svuota
Cosa mi perdo????
grazie a tutti
Titolo: Re:Passare dati a un nuovo thread
Inserito da: nomorelogic - Febbraio 13, 2017, 09:34:30 am
probabilmente (qua mi gioco la reputazione :D) l'oggetto ARequestInfo viene distrutto dal thread principale al rientro da Tusessionthrd.Create
quindi il puntatore nel nuovo thread punta ad un oggetto che è stato distrutto

potresti provare:
1) in TFR_Principale.HTTPServerCommandGet, clona ARequestInfo (ad esempio in ThreadSafeARequestInfo)
2) crea il thread con:
Codice: [Seleziona]
SesThrd:=Tusessionthrd.Create(False,ThreadSafeARequestInfo,AResponseInfo,AContext);
3) assicurati che il thread distrugga ThreadSafeARequestInfo quando ha terminato il lavoro

speriamo bene :)
facci sapere
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Diego1981 - Febbraio 13, 2017, 10:15:06 am
grazie nomore
ora provo ma il dubbio è
se Arequestinfo lo dichiaro nella parte private del mio thread

Tusessionthrd=class(TThread)
    procedure LoginPage;
    ....
    ....
  private
    ARequestInfo:TIdHTTPRequestInfo;
    AResponseInfo:TIdHTTPResponseInfo;
    ....
    ....

come può distruggerlo il thread principale? Non dovrebbe passare ad ARequestinfo le informazioni che vengono allocate in un'altra parte di memoria che ovviamente non corrisponde a quella di RequestInfo (scusa la similitudine dei nomi)
grazie
Titolo: Re:Passare dati a un nuovo thread
Inserito da: nomorelogic - Febbraio 13, 2017, 10:38:59 am
forse non ho capito bene,
se ARequestInfo lo dichiari in private della classe del thread come fa il thread principale ad accedere al valore? Forse ci sono più dichiarazioni con lo stesso nome, una interna al thread principale ed un'altra nel child thread?

Detto questo può anche essere il thread che, nella sua create (e quindi prima di tornare nel main thread), si fa un clone e se lo conserva per il suo utilizzo (per poi distruggerlo al termine).

Consiglio: Il puntatore nel thread lo chiamerei ThreadRequestInfo.
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Diego1981 - Febbraio 13, 2017, 10:52:48 am
riprovo avendo moficiato i nomi, spero crei meno confusione

form principale

procedure TFR_Principale.HTTPServerCommandGet(AContext: TIdContext;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo);
begin
SesThrd:=Tusessionthrd.Create(False,ARequestInfo,AResponseInfo,AContext);
end;

thread Tusessionthrd

Tusessionthrd=class(TThread)
    procedure ....
    ....
    ....
  private
    ThrdARequestInfo:TIdHTTPRequestInfo;
    ....
    ....
  public
    constructor Create(CreateSuspended:Boolean;
ARequestInfo:TIdHTTPRequestInfo;AResponseInfo:TIdHTTPResponseInfo;
      Acontext:TIdContext);

protected
    procedure Execute; override;

  end;
 

constructor Tusessionthrd.Create(CreateSuspended: Boolean;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo;
  Acontext: TIdContext);
begin NEL COSTRUTTORE PASSO LA CLASSE "AREQUESTINFO" CHE ARRIVA DALLA FORM PRINCIPALE ALLA CLASSE PRIVATA "THRDAREQUESTINFO" DEL THREAD
  inherited Create(CreateSuspended);
  ThrdARequestInfo:=TIdHTTPRequestInfo.Create;
  ThrdARequestInfo:=ARequestInfo; NON E' QUI CHE VIENE ALLOCATA IN UNA NUOVA PARTE DI MEMORIA LA NUOVA CLASSE ?????O MEGLIO...LA CLASSE COPIATA
....
....
....


vedi se è più chiaro
grazie

Titolo: Re:Passare dati a un nuovo thread
Inserito da: nomorelogic - Febbraio 13, 2017, 11:28:04 am
constructor Tusessionthrd.Create(CreateSuspended: Boolean;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo;
  Acontext: TIdContext);
begin NEL COSTRUTTORE PASSO LA CLASSE "AREQUESTINFO" CHE ARRIVA DALLA FORM PRINCIPALE ALLA CLASSE PRIVATA "THRDAREQUESTINFO" DEL THREAD
  inherited Create(CreateSuspended);
  ThrdARequestInfo:=TIdHTTPRequestInfo.Create;
  ThrdARequestInfo:=ARequestInfo; NON E' QUI CHE VIENE ALLOCATA IN UNA NUOVA PARTE DI MEMORIA LA NUOVA CLASSE ?????O MEGLIO...LA CLASSE COPIATA

Prova così

Codice: [Seleziona]
constructor Tusessionthrd.Create(CreateSuspended: Boolean;
  ARequestInfo: TIdHTTPRequestInfo; AResponseInfo: TIdHTTPResponseInfo;
  Acontext: TIdContext);
begin // NEL COSTRUTTORE PASSO LA CLASSE "AREQUESTINFO" CHE ARRIVA DALLA FORM PRINCIPALE
  inherited Create(CreateSuspended);
  ThrdARequestInfo:=TIdHTTPRequestInfo.Create;  // crea nuova istanza e valorizza puntatore
  ThrdARequestInfo.Assign(ARequestInfo); // copia i valori nell'istanza ThrdARequestInfo leggendo da istanza ARequestInfo
  ...

quando mandi in esecuzione vedi se ARequestInfo è valorizzato e se si valorizza ThrdRequestInfo
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Diego1981 - Febbraio 13, 2017, 01:06:20 pm
Avevo già provato anche questa forma ma ThrdArequestInfo non si valorizza
 :o
Titolo: Re:Passare dati a un nuovo thread
Inserito da: nomorelogic - Febbraio 13, 2017, 03:17:49 pm
ARequestInfo è valorizzato?
Titolo: Re:Passare dati a un nuovo thread
Inserito da: xinyiman - Febbraio 13, 2017, 03:25:01 pm
Fai prima a mettere un esempio che replica il problema...così ti possiamo aiutare senza andare alla cieca
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Diego1981 - Febbraio 13, 2017, 04:33:23 pm
allora
usando:
ThrdARequestInfo:=TIdHTTPRequestInfo.Create;
ThrdARequestInfo:=ARequestInfo;

ThrdArequestinfo si valorizza (almeno nell' Analizzatore di debug vedo i parametri inviati dalla pagina html) ma come tento di accede and una proprietà dal thread(per esempio ThrdArequestInfo.Document) e non dalla form principale la classe si vuota completamente

mentre usando
ThrdARequestInfo:=TIdHTTPRequestInfo.Create;
ThrdARequestInfo.Assign(ARequestInfo);

ThrdArequestinfo non si valorizza proprio

PS
ciao xiny provo a copiare due righe in nuovo progetto e le mando, grazie
comunque mi sembra di capire che il threadprincipale finisce la sua procedura (CommandGet in questo caso) e ArequestInfo inviato al costruttore del thread si svuoti/annulla/distrugge (come dir si voglia  :o) e di conseguenza anche tutto il resto sparisce..... ci potrebbe stare?
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Diego1981 - Febbraio 14, 2017, 07:49:45 am
risolto!!
nomore, approposito di reputazione(la mia), la procedura CommandGet è gia in multithread...azz  :-X

scusate la comfusione
Titolo: Re:Passare dati a un nuovo thread
Inserito da: SB - Febbraio 14, 2017, 10:38:03 am
ThrdARequestInfo:=TIdHTTPRequestInfo.Create;
ThrdARequestInfo:=ARequestInfo;
 :o
stai sovrascrivendo un oggetto appena creato nel thread secondario con un riferimento passato dal thread principale che può non avere alcun significato nel thread secondario...
 :o
mi meraviglio che il debugger faccia vedere qualcosa... probabilmente fa vedere le proprietà dell'oggetto originale fino al refresh della scheda

per funzionare devi creare l'oggetto in memoria condivisa e proteggere l'accesso almeno con una sezione critica

per curiosità, come hai risolto?


Titolo: Re:Passare dati a un nuovo thread
Inserito da: xinyiman - Febbraio 14, 2017, 11:25:56 am
SB, sai penso ci sia bisogno di un articoletto su questo tema. Te la senti di scrivere qualcosa con un piccolo esempio, almeno anche per il futuro basterà indicare tale articolo per far capire alle persone dove e come agire!
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Diego1981 - Febbraio 14, 2017, 12:59:16 pm
Ciao SB
ho risolto rileggendo per la 1000esima volta la procedura CommandGet e provando a mettere uno sleep....ad altre richieste la procedura funzionava perfettamente quindi non c'è bisogno di altri thread
ora però sto litiganto con mysql per il savattaggio dei dati quando ci sono più richieste nello stesso momento da piu pagine (ma questo è un altro problema)
grazie mille comunque
Titolo: Re:Passare dati a un nuovo thread
Inserito da: SB - Febbraio 14, 2017, 02:16:26 pm
Se ho intuito cosa stai facendo...
Attento che lo sleep sospende il thread corrente facendone subentrare un altro, ma è come nascondere la polvere sotto il tappeto... prima o poi il problema salta fuori...
Non ho mai usato la CommandGet, ma se hanno fatto le cose sofisticate e creano un thread separato per ogni richiesta, devi organizzare il codice in maniera tale da risolvere tutto dentro il gestore dell'evento, senza riferimento ad oggetti esterni (es. riferimenti alla connessione al database)
Ricorda che ogni thread "vede" solo ciò che si è creato, e la memoria globale (esplicitamente) condivisa
Gli accessi alla memoria condivisa vanno assolutamente regolati. Il meccanismo più semplice sono le sezioni critiche.
Altra cosa da ricordare è che per questioni di efficienza non tutte le api di sistema o le librerie esterne (es. quelle di accesso ai database) sono previste per il multithreading. Si rischiano dei bei casini.
Bisogna assicurarsi (vedere documentazione, di solito è esplicitamente indicato) che siano multithreading, e se non lo sono bisogna ricorrere ai meccanismi di regolazione disponibili (sezioni critiche, mutex, semafori, ecc)
Infine, per testare il server devi organizzare una batteria di client che vada giù di brutto con le richieste, altrimenti non vedi i possibili problemi e sul più bello si blocca tutto.
Non so se il debugger di Lazarus sia multithreading (mi sembra strano), ma di solito non si riesce a debuggare bene con più thread. Devi ingegnarti a controllare il funzionamento del codice.
Un server è una bella gatta da pelare... buona fortuna...
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Diego1981 - Febbraio 14, 2017, 05:12:11 pm
Ciao SB
infatti come dici tu, tutto deve restare dentro alla procedura altrimenti salta fuori un bel pastrocchio, per capirsi, rischi che i dati si mescolino tra loro qualora più client effettuino richieste di scrittura sui db....mi sto divertendo insomma :-X
inoltre le librerie indy ,almeno per me, non sono di certo un libro aperto semplice da leggere e capire
grazie delle utili spiegazioni
Titolo: Re:Passare dati a un nuovo thread
Inserito da: SB - Febbraio 14, 2017, 06:35:37 pm
Se c'è il problema di mescolamento dei dati prova a valutare la possibilità di realizzare una coda di scrittura.
In altre parole, ogni thread di risposta mette i dati in una coda (attenzione ai meccanismi di sincronizzazione) gestita da un ulteriore thread che fa da interfaccia con il database.
In questo modo hai un solo thread che opera col database e non ci sono più sovrapposizioni. Forse solo un calo di prestazioni.


Titolo: Re:Passare dati a un nuovo thread
Inserito da: Stilgar - Febbraio 15, 2017, 01:06:36 am
Ciao sb.
L'idea mi fa venire in mente le code mq.
A questo punto non conviene mettere un tomcat e è una coda mq per poi scodare con calma?
Forse manca qualcosa tipo spring integration nel mondo freepascal. Tutte ste cosine arrivano relativamente gratis.
Diego prova a vedere se esiste qualcosa di utile ai tuoi scopi a questo indirizzo http://activemq.apache.org/delphi-and-freepascal.html
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Stilgar - Febbraio 15, 2017, 01:09:31 am
Anzi a questo https://mikejustin.wordpress.com/2017/02/02/habari-client-libraries-release-2017-02/ più recente
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Stilgar - Febbraio 15, 2017, 01:17:20 am
https://github.com/fabriciocolombo/delphi-rest-client-api/blob/master/README.markdown

Anche qui potresti trovare qualche cosa che ti può ispirare.
Sempre con indy
Titolo: Re:Passare dati a un nuovo thread
Inserito da: Diego1981 - Febbraio 15, 2017, 01:26:26 pm
Ciao Stilgar
grazie anche a te, vedo che comunque il multhreading appassiona sempre.  ;D
Sto procedento ma con grosse difficoltà, ora sono all'errore socket error #10093
In sostanza è una pagina di registrazione che se viene inviata da un solo client tutto va bene mentre se più client (per ora la mia batteria è di 4  ;D ;D come diceva SB )
tutti i dati vengono scritti sul db ma l'errore poi blocca tutto