Estoy creando una aplicación de consola que necesita ejecutar varios subprocesos para realizar una tarea. Mi problema es que los hilos se están ejecutando uno tras otro (thread1 start -> work -> end y ONLY then start thread2) en lugar de ejecutar todo al mismo tiempo. Además, no quiero que más de 10 subprocesos funcionen al mismo tiempo (problemas de rendimiento). Bellow es un código de ejemplo de aplicación de consola y del módulo de datos utilizado. mi aplicación está trabajando de la misma manera. He utilizado un módulo de datos porque después de que los hilos terminen, debo completar una base de datos con esas informaciones. También hay comentarios en el código para explicar cuál es el motivo para hacer algo.¿Por qué los hilos se ejecutan en serie en esta aplicación de consola?
aplicación de código consola:
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.
y módulo de datos de código
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.
así, como he dicho el problema es que mis hilos se ejecutan uno tras otro, en lugar de trabajar todos en la Mismo tiempo. También he visto que a veces solo funcionaba el primer subproceso, después de eso todo el resto solo creaba y terminaba. en mi aplicación, todo el código está protegido por try-excepts, pero no se generan errores.
¿Puede alguien darme un consejo?
Una buena forma de garantizar que no se ejecuten más de 10 subprocesos al mismo tiempo es utilizar un * semáforo *. Adquirirlo antes de crear un hilo, y hacer que cada hilo lo libere al finalizarlo. Si ya hay 10 subprocesos en ejecución, el undécimo intento de adquirir el semáforo se bloqueará hasta que termine otro subproceso. Entonces no necesita los bucles de espera de espera de ProcessMessages. Esos bucles no hacen más que consumir tiempo de CPU porque tu aplicación nunca * envía * ningún mensaje, por lo que nunca habrá nada que procesar. –
Otro paso que puede tomar es llamar a 'CheckSynchronize' cuando realmente hay algo con lo que sincronizar. Con su configuración de semáforo, llame a MsgWaitForMultipleObjects en el control del semáforo y la variable global 'SyncEvent'. Lea sobre esto en Classes.pas. Si se señala el semáforo, crea un nuevo hilo. Si se señala el evento, llame a CheckSynchronize. –
Rob, muchas gracias por la información. He leído acerca de los semáforos, pero no estoy seguro de que entiendo completamente cómo debería implementarlo. por lo que he leído, necesito usar WaitForSingleObject (handle, infinite) para que el hilo termine todo el ciclo, pero ¿cómo puedo saber cuándo iniciar otro hilo? He visto algunos ejemplos, así que creo que debo crear un semáforo con 10 hilos, pero al disminuir la forma en que estoy creando un nuevo hilo y almorzarlo en semáforo? ¿alguien me puede dar un pequeño ejemplo basado en mi ejemplo? gracias de antemano! – RBA