Sto creando un'applicazione console che deve eseguire diversi thread per eseguire un'attività. Il mio problema è che i thread sono in esecuzione uno dopo l'altro (thread1 start -> lavoro -> fine e SOLO quindi avviare thread2) invece di eseguire tutto nello stesso tempo. Inoltre, non voglio che più di 10 thread funzionino nello stesso tempo (problemi di prestazioni). Bellow è un codice di esempio dell'applicazione console e del datamodule utilizzato. la mia applicazione funziona allo stesso modo. ho usato un datamodule perché dopo che i thread sono finiti devo riempire un database con quelle informazioni. Inoltre ci sono commenti nel codice per spiegare quale è la ragione per fare qualcosa.Perché i thread vengono eseguiti in serie in questa applicazione console?
app codice console:
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils,
Unit1 in 'Unit1.pas' {DataModule1: TDataModule};
var dm:TDataModule1;
begin
dm:=TDataModule1.Create(nil);
try
dm.execute;
finally
FreeAndNil(dm);
end;
end.
e datamodule codice
unit Unit1;
interface
uses
SysUtils, Classes, SyncObjs, Windows, Forms;
var FCritical: TRTLCriticalSection;//accessing the global variables
type
TTestThread = class(TThread)
protected
procedure Execute;override;
end;
TDataModule1 = class(TDataModule)
procedure DataModuleCreate(Sender: TObject);
procedure DataModuleDestroy(Sender: TObject);
private
{ Déclarations privées }
public
procedure execute;
procedure CreateThread();
procedure Onterminatethrd(Sender: TObject);
end;
var
DataModule1 : TDataModule1;
FthreadCount : Integer; //know how many threads are running
implementation
{$R *.dfm}
{ TTestThread }
procedure TTestThread.Execute;
var
f : TextFile;
i : integer;
begin
EnterCriticalSection(fcritical);
AssignFile(f, 'd:\a' + inttostr(FthreadCount) + '.txt');
LeaveCriticalSection(fcritical);
Rewrite(f);
try
i := 0;
while i <= 1000000 do // do some work...
Inc(i);
Writeln(f, 'done');
finally
CloseFile(f);
end;
end;
{ TDataModule1 }
procedure TDataModule1.CreateThread;
var
aThrd : TTestThread;
begin
aThrd := TTestThread.Create(True);
aThrd.FreeOnTerminate := True;
EnterCriticalSection(fcritical);
Inc(FthreadCount);
LeaveCriticalSection(fcritical);
aThrd.OnTerminate:=Onterminatethrd;
try
aThrd.Resume;
except
FreeAndNil(aThrd);
end;
end;
procedure TDataModule1.Onterminatethrd(Sender: TObject);
begin
EnterCriticalSection(fcritical);
Dec(FthreadCount);
LeaveCriticalSection(fcritical);
end;
procedure TDataModule1.DataModuleCreate(Sender: TObject);
begin
InitializeCriticalSection(fcritical);
end;
procedure TDataModule1.DataModuleDestroy(Sender: TObject);
begin
DeleteCriticalSection(fcritical);
end;
procedure TDataModule1.execute;
var
i : integer;
begin
i := 0;
while i < 1000 do
begin
while (FthreadCount = 10) do
Application.ProcessMessages;//wait for an thread to finish. max threads at a //time =10
CreateThread;
EnterCriticalSection(fcritical);
Inc(i);
LeaveCriticalSection(fcritical);
while FthreadCount > 0 do //wait for all threads to finish in order to close the //main thread
begin
Application.ProcessMessages;
CheckSynchronize;
end;
end;
end;
end.
modo, come ho detto il problema è che le mie discussioni sono in esecuzione una dopo l'altra, invece di lavorare tutti nella contemporaneamente. ho anche visto che a volte solo il primo thread ha funzionato, dopodiché tutto il resto è stato creato e completato. nella mia applicazione tutto il codice è protetto da try-excepts ma non vengono sollevati errori.
Qualcuno può darmi un consiglio?
Un buon modo per assicurarsi che non vengano eseguiti più di 10 thread in una sola volta è utilizzare un * semaforo *. Acquistalo prima di creare un thread e fai in modo che ogni thread lo rilasci al termine. Se sono già in esecuzione 10 thread, l'undicesimo tentativo di acquisire il semaforo verrà bloccato fino alla chiusura di un altro thread. Quindi non sono necessari quei loop di attesa-attesa di ProcessMessages. Questi loop non fanno altro che consumare il tempo della CPU perché la tua applicazione non invia mai * alcun messaggio, quindi non ci sarà mai nulla da elaborare. –
Un altro passo che puoi compiere è chiamare "CheckSynchronize" solo quando c'è effettivamente qualcosa con cui sincronizzarsi. Con la configurazione del semaforo, chiama MsgWaitForMultipleObjects sull'handle del semaforo e la variabile globale 'SyncEvent'. Leggi in Classes.pas. Se viene segnalato il semaforo, creare un nuovo thread. Se viene segnalato l'evento, chiamare CheckSynchronize. –
Rob, grazie mille per le informazioni. Ho letto ora dei semafori, ma non sono sicuro di comprendere appieno come dovrei implementarlo. da quello che ho letto ho bisogno di usare WaitForSingleObject (handle, infinito) - perché il thread finisca l'intero ciclo, ma come posso sapere quando iniziare un altro thread? Ho visto alcuni esempi quindi credo che devo creare un semaforo con 10 thread, ma quando diminuisco come sto creando un nuovo thread e lo pranziamo nel semaforo? qualcuno può fornirmi un piccolo esempio basato sul mio esempio? grazie in anticipo! – RBA