* * * *

Privacy Policy

Blog italiano

Clicca qui se vuoi andare al blog italiano su Lazarus e il pascal.

Forum ufficiale

Se non siete riusciti a reperire l'informazione che cercavate nei nostri articoli o sul nostro forum vi consiglio di visitare il
Forum ufficiale di Lazarus in lingua inglese.

Lazarus 1.0

Trascinare un file nel programma
DB concetti fondamentali e ZeosLib
Recuperare codice HTML da pagina web
Mandare mail con Lazarus
Stabilire il sistema operativo
Esempio lista in pascal
File INI
Codice di attivazione
Realizzare programmi multilingua
Lavorare con le directory
Utilizzare Unità esterne
TTreeView
TTreeview e Menu
Generare controlli RUN-TIME
LazReport, PDF ed immagini
Intercettare tasti premuti
Ampliare Lazarus
Lazarus e la crittografia
System Tray con Lazarus
UIB: Unified Interbase
Il file: questo sconosciuto
Conferma di chiusura di un applicazione
Liste e puntatori
Overload di funzioni
Funzioni a parametri variabili
Proprietà
Conversione numerica
TImage su Form e Panel
Indy gestiore server FTP lato Client
PopUpMenu sotto Pulsante (TSpeedButton)
Direttiva $macro
Toolbar
Evidenziare voci TreeView
Visualizzare un file Html esterno
StatusBar - aggirare l'errore variabile duplicata
Da DataSource a Excel
Le permutazioni
Brute force
Indy 10 - Invio email con allegati
La gestione degli errori in Lazarus
Pascal Script
Linux + Zeos + Firebird
Dataset virtuale
Overload di operatori
Lavorare con file in formato JSON con Lazarus
Zeos ... dietro le quinte (prima parte)
Disporre le finestre in un blocco unico (come Delphi)
Aspetto retrò (Cmd Line)
Lazarus 1.0
Come interfacciare periferica twain
Ubuntu - aggiornare free pascal e lazarus
fpcup: installazioni parallele di lazarus e fpc
Free Pascal e Lazarus sul Raspberry Pi
Cifratura: breve guida all'uso dell'algoritmo BlowFish con lazarus e free pascal.
Creare un server multithread
guida all'installazione di fpc trunk da subversion in linux gentoo
Indice
DB concetti fondamentali e connessioni standard
Advanced Record Syntax
DB concetti fondamentali e DBGrid
DB concetti fondamentali e TDBEdit, TDBMemo e TDBText
Advanced Record Syntax: un esempio pratico
Superclasse form base per programmi gestionali (e non)
Superclasse form base per programmi gestionali (e non) #2 - log, exception call stack, application toolbox
Superclasse form base per programmi gestionali (e non) #3 - traduzione delle form
Superclasse form base per programmi gestionali (e non) #4 - wait animation
Un dialog per la connessione al database:TfmSimpleDbConnectionDialog
Installare lazarus su mac osx sierra
immagine docker per lavorare con lazarus e free pascal
TDD o Test-Driven Development
Benvenuto! Effettua l'accesso oppure registrati.
Novembre 28, 2024, 05:50:22 am

Inserisci il nome utente, la password e la durata della sessione.

32 Visitatori, 0 Utenti

Autore Topic: Lavorare con i thread  (Letto 18460 volte)

bonmario

  • Hero Member
  • *****
  • Post: 1364
  • Karma: +11/-1
Lavorare con i thread
« il: Settembre 17, 2012, 01:35:39 pm »
Ciao a tutti,
ho un programma che sfrutta un eseguibile esterno per convertire tutti i fiels mp3 in una directory. Praticamente mi faccio l'elenco dei files e poi, uno alla volta, tramite un TProcess, li faccio ricodificare.
Ho provato con una directory di circa 300 fles e ci ha messo quasi un'ora, quindi avevo pensato di velocizzare il tutto lanciando le ricodifiche in parallelo sfruttando i thread, lanciando una decina di ricodifiche in parallelo.
Fino ad ora però ho usato poco i thread e tra l'altro mai in parallelo.
Volevo quindi chiedervi, devo gestire io a programma il n° di thread che possono girare in parallelo o devo impostare qualche variabile?

Grazie in anticipo, Mario

nomorelogic

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2924
  • Karma: +20/-4
Re:Lavorare con i thread
« Risposta #1 il: Settembre 17, 2012, 01:49:12 pm »
ciao,
secondo me se eviti il "wait for terminate", in modo da lanciarli asincronalmente, puoi tranquillamente istanziare 10 TProcess e lanciarli l'uno dietro l'altro.

Ad esempio puoi usare una TObjectList per istanziare e referenziare i 10 (anche 'N' volendo) TProcess. Fatto questo puoi lanciarli uno di seguito all'altro e, nell'OnTerminate di ogni TProcess, ci metti il prelevamento del prossimo file dalla lista.
Imagination is more important than knowledge (A.Einstein)

bonmario

  • Hero Member
  • *****
  • Post: 1364
  • Karma: +11/-1
Re:Lavorare con i thread
« Risposta #2 il: Settembre 18, 2012, 01:39:00 pm »
Ho fatto un programma di test e sembra funzionare tutto !!!
Alla fine, per lacune mie, ho ripiegato su un array di thread invece di usare la TObjectList.

P.S. Qualcuno sa dirmi come valutare come impostare il n° massimo di thread contemporanei? Ho provato con 20 ed il PC sembra reggere, ma siccome il programma dovrà girare anche su altri PC più o meno potenti, volevo evitare di sovradimensionare tale numero.

Grazie ancora, Mario

bonmario

  • Hero Member
  • *****
  • Post: 1364
  • Karma: +11/-1
Re:Lavorare con i thread
« Risposta #3 il: Settembre 25, 2012, 09:08:42 am »
Ciao a tutti,
sto facendo i miei esperimenti sui thread. Allego i sorgenti del progetto di prova.
C'è una cos che proprio non capisco ed è a riga 193, proprio dove c'è il breakpoint impostato.
Praticamente, se all'interno dell'execute del thread, lascio attiva la "Application.ProcessMessages", il thread termina all'istante. Se invece disattivo la ProcessMessages, sembra funzionare tutto correttamente.
Chiedo a voi che siete più esperti di me: è un bug o è normale questo comportamento?

Grazie in anticipo, Mario

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Lavorare con i thread
« Risposta #4 il: Settembre 25, 2012, 09:51:19 am »
Eseguiendo il codice (eliminando i bp) ottengo questo output ... a me sembra lento a chiudere, ma lavora ;)

File n°:   1  -   Thread n°:  1 -
File n°:   2  -   Thread n°:  2 -
File n°:   3  -   Thread n°:  3 -
File n°:   5  -   Thread n°:  4 -
File n°:   4  -   Thread n°:  1 -
File n°:   7  -   Thread n°:  3 -
File n°:   8  -   Thread n°:  4 -
File n°:   9  -   Thread n°:  1 -
File n°:  10  -   Thread n°:  3 -
File n°:  11  -   Thread n°:  4 -
File n°:  12  -   Thread n°:  1 -
File n°:  17  -   Thread n°:  7 -
File n°:  19  -   Thread n°:  9 -
File n°:  21  -   Thread n°:  1 -
File n°:  22  -   Thread n°:  7 -
File n°:  23  -   Thread n°:  9 -
File n°:  15  -   Thread n°:  5 -
File n°:  25  -   Thread n°:  7 -
File n°:  27  -   Thread n°:  5 -
File n°:  24  -   Thread n°:  1 -
File n°:  13  -   Thread n°:  3 -
File n°:  28  -   Thread n°:  7 -
File n°:  29  -   Thread n°:  5 -
File n°:  32  -   Thread n°:  7 -
File n°:  33  -   Thread n°:  5 -
File n°:  31  -   Thread n°:  3 -
File n°:  35  -   Thread n°:  5 -
File n°:  36  -   Thread n°:  3 -
File n°:  37  -   Thread n°:  5 -
File n°:  38  -   Thread n°:  3 -
File n°:  39  -   Thread n°:  5 -
File n°:  34  -   Thread n°:  7 -
File n°:  40  -   Thread n°:  3 -
File n°:  41  -   Thread n°:  5 -
File n°:  42  -   Thread n°:  7 -
File n°:  30  -   Thread n°:  1 -
File n°:  44  -   Thread n°:  5 -
File n°:  45  -   Thread n°:  7 -
File n°:  43  -   Thread n°:  3 -
File n°:  26  -   Thread n°:  9 -
File n°:  49  -   Thread n°:  7 -
In attesa che tutti i thread terminino il proprio lavoro ...
File n°:  47  -   Thread n°:  5 -
File n°:  50  -   Thread n°:  9 -
File n°:  20  -   Thread n°: 10 -
File n°:  18  -   Thread n°:  8 -
File n°:  48  -   Thread n°:  3 -
File n°:  16  -   Thread n°:  6 -
File n°:  14  -   Thread n°:  4 -
File n°:   6  -   Thread n°:  2 -
File n°:  46  -   Thread n°:  1 -
Il thread n° 1 ha appena finito il proprio lavoro
Fine !!!



Files analizzati: 50
Durata del ciclo: 00:00:14
Invece di:        00:12:30

Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

bonmario

  • Hero Member
  • *****
  • Post: 1364
  • Karma: +11/-1
Re:Lavorare con i thread
« Risposta #5 il: Settembre 25, 2012, 10:00:58 am »
Prova ad eseguirlo in debug con il breakpoint sul ProcessMessages.
Con il ProcessMessages attivo, l'istruzione Sleep non viene mai eseguita, ne' tantomeno tittoo quello che c'è dopo "Application.ProcessMessages;".
Se invece disattivi la Application.ProcessMessages e ti rimetti in debug, viene eseguito tutto. Tra l'altro questa cosa non l'ho notata a casa su Linux.

Ciao, Mario

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Lavorare con i thread
« Risposta #6 il: Settembre 25, 2012, 10:14:20 am »
Con i bp mi va in malora Lazarus ... sembra che il debugger sotto win7 abbia qualche difficoltà con i thread ...
Piuttosto notavo 2 cose nel codice:
1) No usi tutte le proprerties della classe thread.
2) Gestisci 2 array, al posto di 1 solo (visto che non interroghi il le properties dei thread non vedo altre strade).
Domanda:
  Come mai hai detto al thread di siucidarsi al termine? Dopo lo recicli .. o non ci ho capito una madonna?
Puoi reimpostare i dati e andare a rilanciarlo (cerca thread libero per intendeci).
La WaitFor sul primo non "terminato" fa si che ti scappi completamente il controllo dei thread.
In questi casi (almeno io faccio così) creao 2 classi.
Un monitor che li controlli e il thread specifico.
Il Thread comunica in modo asincorno lo stato al monitor.
L'applicazione chiede al monitor cosa stanno facendo i thread.
La tua form, in questo caso è il monito in questione. Il fatto che il thread decida autonomamente di suicidarsi va contro l'idea dei thread pool.
Quando deallochi il monitor, questo dealloca il pool di thread.
Se si suoicidano, li sganci e te ne dimentichi.
Sono proprio curioso di sapere come mai nn hai deciso di usare il terminated del thread.
;)
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

bonmario

  • Hero Member
  • *****
  • Post: 1364
  • Karma: +11/-1
Re:Lavorare con i thread
« Risposta #7 il: Settembre 25, 2012, 10:38:51 am »
Sono un novizio dei thread ... ho messo insieme informazioni prese da vari siti.
Dico al thread di suicidarsi perché voglio riciclare i thread quando terminano. Nella "TMyThread.Destroy;" ho aggiunto l'istruzione che va ad impostare il thread come terminato nell'array di controllo che uso.
La WaitFor la faccio solo al termine del ciclo principale, in modo che il programma resti in attesa fino a quando tutti i thred in esecuzione non sono terminati.

Per quanto riguarda il discorso del processmessages, prova così:
Codice: [Seleziona]
  procedure TMyThread.Execute;
  var NomeFileDest:String;
      Idx:Integer;
  begin
    for Idx:=1 to 5 do begin
      Application.ProcessMessages;
      Sleep(1000);
    end;

    Synchronize(@EmettiNomeFile);

    //Forzo la chiusura del Thread. Per qualche motivo, senza questa istruzione,
    //il thread sembrava sempre in esecuzione
    Terminate;
  end;

Praticamente ho solo spostato in basso la Synchronize e, questa non viene più eseguita. Se disattivo la processmessages invece funziona regolarmente.
Qui al lavoro ho Windows XP SP3.

Per me è il primo progarmma "serio" che sviluppo con i thread, quindi qualsiasi consiglio è benvenuto !!!

Ciao, Mario

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Lavorare con i thread
« Risposta #8 il: Settembre 25, 2012, 11:09:41 am »
Allora.
Il Syncronize serve per "stoppare" il thread secondario ed agganciarlo a quello principale. Se devi modificare il GUI è molto ultile ;)
Ti allego un pool scritto di fretta e furia.
Ti posso solo garantire che compila. L'idea è deleare a lui il fatto di gestire i thread.
Ho scoperto con mio sommo disappunto che la properties Terminated è stata nascosta ...  il pool introduce una classe Thread che assomiglia vagamente a quella Java.

Lo start e lo stop sono delegati al monitor ;)
Prova a buttarci un occhio, per farti un'idea :D
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

bonmario

  • Hero Member
  • *****
  • Post: 1364
  • Karma: +11/-1
Re:Lavorare con i thread
« Risposta #9 il: Settembre 25, 2012, 11:36:17 am »
Ho guardato, ma credo che non faccia al caso mio.
Il mio scopo è lanciare in parallelo un lavoro su tutti i files presenti in una directory. Siccome nella directory ci possono essere anche centinaia di files, faccio in modo di lanciare 10 conversioni contemporaneamente. man mano che una finisce, libera il relativo hread che può essere quindi occupato dal file successivo.
Se non ho capito male il tuo codice, con quello dovrei preparare prima tutti i thread e poi farli partire con StartPool. Se non è così allora non ci ho capito niente !!!!

In ogni caso, tornando alla domanda iniziale, a voi risulta che Application.ProcessMessages  non possa essere usata nella Execute di un thread perché la sua chiamata fa terminare il thread immediatamente?

Ciao, Mario

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Lavorare con i thread
« Risposta #10 il: Settembre 25, 2012, 11:47:36 am »
Mario, il codice non voleva essere una soluzione, ma un suggerimento su come gestire i thread.
Il "ProcessMessage" serve per prelevare dalla cosa dei messaggi (Windows almeno) e fare il dispatch ai controlli dell'applicazione stessa.
Se tu prelevi da un thread secondario i messaggi, potresti avere dei comportamenti anomali.
Il thread principale vedilo come un thread di "paint" e "read input".
Nei video giochi questi sono due thread distinti, per aumentare la fluidità delle immagini, ma in un gestionale non hai problemi di frame rate ;)
In linea di massima nulla ti vieta di forzare il process dei messaggi.
Leggevo qualche cosa sul fatto che è sconsigliato .... (Wiki di Lazarus, se ricordo bene).
Anzi, loro sconsigliavano proprio l'uso dei thread :D
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

bonmario

  • Hero Member
  • *****
  • Post: 1364
  • Karma: +11/-1
Re:Lavorare con i thread
« Risposta #11 il: Settembre 28, 2012, 05:04:06 pm »
Come mai hai detto al thread di siucidarsi al termine?

Mi è venuto in mente oggi facendo altre prove: ho notato che se non metto l'istruzione "Terminate;" alla fine della "Execute" e poi, in altre parti del programma, vado a testare "MyThread.Terminated", quest'ultima mi da dei risultati errati, dicendomi che dei thread non sono terminati anche se invece lo sono. Facendo come ho fatto io, invece, se testo "MyThread.Terminated" mi da sempre il risultato corretto.
Non so se è un bug di Lazarus, ma dalle prove che ho fatto ho notato questo.

Ciao, Mario

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Lavorare con i thread
« Risposta #12 il: Settembre 28, 2012, 11:42:32 pm »
Ciao Mario,
 allora non penso sia un problema del lazzarone o della libreria base.
Credo che il terminate (se controlli il codice puoi verificare da solo) non faccia altro che indicare FTerminate := true;
Codice: [Seleziona]
//estratto dal file classes.inc riga 78
function ThreadProc(ThreadObjPtr: Pointer): PtrInt;
  var
    FreeThread: Boolean;
    Thread: TThread absolute ThreadObjPtr;
  begin
    { if Suspend checks FSuspended before doing anything, make sure it }
    { knows we're currently not suspended (this flag may have been set }
    { to true if CreateSuspended was true)                             }
//    Thread.FSuspended:=false;
    // wait until AfterConstruction has been called, so we cannot
    // free ourselves before TThread.Create has finished
    // (since that one may check our VTM in case of $R+, and
    //  will call the AfterConstruction method in all cases)
//    Thread.Suspend;
    try
      { The thread may be already terminated at this point, e.g. if it was intially
        suspended, or if it wasn't ever scheduled for execution for whatever reason.
        So bypass user code if terminated. }
      if not Thread.Terminated then
        Thread.Execute;
    except
      Thread.FFatalException := TObject(AcquireExceptionObject);
    end;
    FreeThread := Thread.FFreeOnTerminate;
    Result := Thread.FReturnValue;
    Thread.FFinished := True;
    Thread.DoTerminate;
    if FreeThread then
      Thread.Free;
    EndThread(Result);
  end;
In effetti il DoTerminate di TThread non è proprio come me lo aspettavo :
Codice: [Seleziona]
//Riga 49
procedure TThread.DoTerminate;
begin
  if Assigned(FOnTerminate) then
    Synchronize(@CallOnTerminate);
end;
Questi thread non fanno altro che chiamare una callback quando terminano, ma non indicano da nessuna parte che sono finiti. Come se prevedessero (in fase di progettazione di comunicare con una sorta di controller esterno).
Come vedi impostano il FFinished e non il FTerminate.
Quindi mi sembra che sia il caso di indicare che è "terminated" a mano ....
Se c'è qualcuno che è in grado di verificare il codice Delphi per questa classe, mi toglierebbe un dubbio ... a naja mi sembrava impostasse il FTerminated ... del Finisched non ho proprio la minima alba.
PS:
  Ma sono l'unico che si mette a guardare il codice delle librerie? Sono così smanettone? :(
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

bonmario

  • Hero Member
  • *****
  • Post: 1364
  • Karma: +11/-1
Re:Lavorare con i thread
« Risposta #13 il: Settembre 29, 2012, 09:07:53 am »
  Ma sono l'unico che si mette a guardare il codice delle librerie? Sono così smanettone? :(

No, ogni tanto ci guardo anch'io, solo che il mio livello è basso basso e quando trovo qualcosa che non capisco ed ho poco tempo vado in fiducia !!!
Se invece ho tempo per fare prove, cerco di sbatterci la testa !!!

Ciao, Mario

Stilgar

  • Global Moderator
  • Hero Member
  • *****
  • Post: 2389
  • Karma: +10/-0
Re:Lavorare con i thread
« Risposta #14 il: Settembre 29, 2012, 07:20:28 pm »
Vuol dire che non sono l'unico smanettone del forum :D
Bene. ;)
Al mondo ci sono 10 tipi di persone ... chi capisce il binario e chi no.

 

Recenti

How To

Utenti
  • Utenti in totale: 802
  • Latest: maXim.FI
Stats
  • Post in totale: 19218
  • Topic in totale: 2291
  • Online Today: 33
  • Online Ever: 900
  • (Gennaio 21, 2020, 08:17:49 pm)
Utenti Online
Users: 0
Guests: 32
Total: 32

Disclaimer:

Questo blog non rappresenta una testata giornalistica poiché viene aggiornato senza alcuna periodicità. Non può pertanto considerarsi un prodotto editoriale ai sensi della legge n. 62/2001.