2011-01-25 10 views
5

Ora ho un'app quasi completa e la funzione successiva che voglio implementare è il threading. Ho scelto di andare con BeginThread(), anche se sono a conoscenza di TThread in delphi. Il problema che sto incontrando è la struttura della chiamata BeginThread(). Normalmente la linea di programma che chiama la funzione voglio essere filettato èBeginThread Structure - Delphi

CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op); 

op è un numero intero.

La linea che ho passato fuori per creare un filo da essa è

BeginThread(nil,0,CompareFiles,Addr('form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op'),0,x); 

Dalla piccola quantità di infromation posso trovare su come utilizzare effettivamente BeginThread() questo dovrebbe essere un bene chiamata tuttavia, il complimento di tutto ciò che ottengo è un errore di complier sulla struttura dei miei parametri di istruzione BeginThread().

MODIFICA PER INFORMAZIONI.

La procedura attuale che chiama CompareFiles è

procedure TForm1.Panel29Click(Sender: TObject); 
var 
op,x : integer; 

begin 
    if (Form1.Edit3.Text <> '') AND (Form1.Edit4.Text <> '') then 
     begin 
      op := 3; 
      if RadioButton7.Checked = True then op := 0; 
      if RadioButton3.Checked = True then op := 1; 
      if RadioButton4.Checked = True then op := 2; 
      if RadioButton5.Checked = True then op := 3; 
      if RadioButton6.Checked = True then op := 4; 
      CompareFiles(form1.Edit3.Text,Form1.Edit4.Text,Form1.StringGrid2,op); 
     end; 
end; 

Se dovessi usare TThread come suggerito da un paio di persone, e come visualizzato da Rob sotto, sono confuso a come a) sarei passato op, Edit3/4.Text e StringGrid2 su CompareFiles. Indovinare dall'esempio di TThread che ho visto ho pensato di sostituire il codice precedente con TCompareFilesThread.Execute e mettere il codice corrente Panel29Click in TCompareFilesThread.Create e quindi aggiungere

FEdit3Text := Edit3Text; 
FEdit4Text := Edit4Text; 
FGrid := Grid; 

a questo

FEdit3Text := Form1.Edit3.Text; 
FEdit4Text := Form1.Edit4.Text; 
FGrid := Form1.StringGrid2; 

Ma Ho questa sensazione fastidiosa che è totalmente fuori luogo.

+0

"I reclami su cose che non corrispondono" non è una descrizione molto utile. Potresti modificare la tua domanda e incollare una copia del messaggio di errore per favore? –

+2

Sono anche curioso del perché tu stia scegliendo * non * di usare TThread? L'uso di funzioni di thread globali senza un piacevole object encapsulation complica enormemente le cose relative alla concorrenza e alle condizioni di gara. Sono anche curioso del perché ti stai avvicinando al completamento dell'applicazione e poi ho deciso di aggiungere il threading. IMO, il threading dovrebbe essere considerato fin dall'inizio e non un ripensamento. Esiste un'alta probabilità di infilare mine terrestri se non prese in considerazione abbastanza presto. –

+0

Il motivo per cui il threading è stato implementato ora è che questa è un'app di apprendimento per me. Il threading è sempre stato pianificato, ma si limita a implementarlo ora che le funzionalità principali dell'app sono complete (soprattutto). Per quanto riguarda TThread, non riesco a trovare una buona spiegazione su come usarlo. – jskrwyk

risposta

14

Questo non è per tutto il modo di utilizzare BeginThread. Quella funzione si aspetta un puntatore a una funzione che prende un parametro, ma la funzione che stai cercando di chiamare vuole quattro. L'unico parametro che stai dando a BeginThread affinché possa inoltrare alla procedura del thread è una stringa, ma tu speri evidentemente che una sorta di magia trasformerà quella stringa di caratteri nei valori che queste variabili contengono.

questo non è come funziona Delphi, e anche per le lingue che possono fare una cosa del genere, è generalmente scoraggiato effettivamente fare esso.

passare più parametri a BeginThread, definire un record con tutti i valori di cui ha bisogno, e anche definire un puntatore del record:

type 
    PCompareFilesParams = ^TCompareFilesParams; 
    TCompareFilesParams = record 
    Edit3Text, 
    Edit4Text: string; 
    Grid: TStringGrid; 
    Op: Integer; 
    end; 

Change CompareFiles ad accettare un puntatore a tale record:

function CompareFiles(Params: PCompareFilesParams): Integer; 

per avviare la discussione, è necessario allocare un'istanza di quel disco e popolare i suoi campi:

var 
    Params: PCompareFilesParams; 
begin 
    New(Params); 
    Params.Edit3Text := Edit3.Text; 
    Params.Edit4Text := Edit4.Text; 
    Params.Grid := StringGrid2; 
    Params.Op := op; 
    BeginThread(nil, 0, @CompareFiles, Params, 0, x); 

Implementare CompareFiles come questo in modo che il record sarà ottenere liberato prima che il thread termina:

function CompareFiles(Params: PCompareFilesParams): Integer; 
begin 
    try 
    // <Normal implementation goes here.> 
    finally 
    Dispose(Params); 
    end; 
end; 

Si può fare tutto molto più facile se si utilizza TThread, però. Puoi fare in modo che la classe discendente abbia tutti i parametri che desideri nel suo costruttore, quindi non devi scherzare con l'allocazione e la liberazione dinamica di un record speciale.

type 
    TCompareFilesThread = class(TThread) 
    private 
    FEdit3Text, 
    FEdit4Text: string; 
    FGrid: TStringGrid; 
    FOp: Integer; 
    procedure Execute; override; 
    public 
    constructor Create(const Edit3Text, Edit4Text: string; Grid: TStringGrid; Op: Integer); 
    property ReturnValue; 
    end; 

constructor TCompareFilesThread.Create; 
begin 
    inherited Create(False); 
    FEdit3Text := Edit3Text; 
    FEdit4Text := Edit4Text; 
    FGrid := Grid; 
    FOp := Op; 
end; 

procedure TCompareFilesThread.Execute; 
begin 
    ReturnValue := CompareFiles(FEdit3Text, FEdit4Text, FGrid, FOp); 
end; 

Invece di chiamare BeginThread, basta creare un'istanza della classe e farlo funzionare:

var 
    ThreadRef: TThread; 


ThreadRef := TCompareFilesThread.Create(Edit3.Text, Edit4.Text, StringGrid2, Op); 

C'è di più a che utilizzano le discussioni, come sapere quando il filo ha terminato l'esecuzione, ma penso che tu abbia abbastanza per iniziare Un'ultima cosa da notare, però, è che TStringGrid è un controllo VCL. Non devi fare nulla con questo da questo nuovo thread che crei (indipendentemente da come finisci per crearlo). Tutto quello che fai con il controllo della griglia deve essere fatto dal thread principale. Utilizzare TThread.Synchronize e TThread.Queue per spostare qualsiasi operazione VCL sul thread principale. Il thread di confronto file attenderà il completamento dell'operazione sincronizzata, ma continuerà a essere in esecuzione senza attendere il completamento di un'operazione in coda.

+0

+1 per la grande spiegazione! ma "Elimina (Params);" dovrebbe essere "Dispose (Params);" – arthurprs

+0

@Arthurprs Oops! Puoi dire che uso C++ tutto il giorno? –

+0

Se riesco a capire come usare TThread, lo farò. Ad esempio con il codice di esempio che hai lì, come/come lo chiamerei nella Procedura di OnClick, che imposta op e decide quando eseguire CompareFiles. – jskrwyk

Problemi correlati