Ok esto es muy interesante, admito como siempre que multithreading es dificil y me cuesta dominarlo. Pero encima en consola es distinto porque se te cierra el programa
Esto es lo que invente, es bastante "versatil"
Clase que hereda de TThread:
Código Delphi
[-]
unit Unit4;
interface
uses
Classes;
type
TThreadInutil = class(TThread)
private
FName: string;
FTope: Int64;
FUltimoValor: Int64;
protected
procedure Execute; override;
public
constructor Create(CreateSuspended: Boolean; const AName: string; const ATope: Int64);
property Name: string read FName;
property Tope: Int64 read FTope;
property UltimoValor: Int64 read FUltimoValor;
end;
implementation
uses
SysUtils;
constructor TThreadInutil.Create(CreateSuspended: Boolean; const AName: string; const ATope: Int64);
begin
inherited Create(CreateSuspended);
FreeOnTerminate := True;
FName := AName;
FUltimoValor := 0;
if FTope > MaxLongint then
FTope := MaxLongint
else
FTope := ATope;
end;
procedure TThreadInutil.Execute;
var
I: Int64;
begin
I := 0;
while (I < Tope) and not Terminated do
begin
Inc(I);
FUltimoValor := I;
Synchronize(NIL, procedure begin WriteLn(Format('Name: %s I = %d', [Name, I])); end);
end;
end;
end.
Basicamente cuenta desde 0 hasta el numero que le decimos en el constructor
En el metodo Execute que es reimplementado, imprime el "nombre" y el numero actual en la salida estandar, usando
Syncronize
El programa principal crea dos TThreadInutiles, los cuales inician apenas termina su correspondiente constructor.
Luego, hay una pequeña clase TInformador porque el evento OnTerminate es de tipo TNotifyEvent y para agregarle un manejador hay que tener un objeto (TNotifyEvent es un procedure of object, no podes poner un procedimiento suelto, a menos no de forma idiomatica)
El informador recibe la notificacion cuando cada hilo termina su trabajo, y si es el "t1", le agrego una lectura de entrada estandar pidiendo un numero: si es 0 le pedimos al t2 que termine, sino que continue
Hay que consultar el estado de los Thread, si estan trabajando (propiedad Booleana Finished) y si alguno esta haciendo algo, es necesario invocar a CheckSyncronize
Código Delphi
[-]
program Project2;
{$APPTYPE CONSOLE}
uses
SysUtils,
Classes,
Unit4 in 'Unit4.pas';
type
TInformador = class
public
procedure ThreadTerminado(Sender: TObject);
end;
var
t1, t2: TThreadInutil;
Informador: TInformador;
procedure TInformador.ThreadTerminado(Sender: TObject);
var
Num: Integer;
begin
Writeln(Format('%s Termino: Ultimo Valor %d', [Sender.ClassName, TThreadInutil(Sender).UltimoValor]));
if Sender = t1 then
begin
Writeln('Ingrese 0 para detener t2, cualquier numero para seguir..');
Readln(Num);
if Num = 0 then
t2.Terminate;
end;
end;
begin
Informador := TInformador.Create;
t1 := TThreadInutil.Create(False, 'Thread 1', 1500);
t2 := TThreadInutil.Create(False, 'Thread 2', 1900);
try
t1.OnTerminate := Informador.ThreadTerminado;
t2.OnTerminate := Informador.ThreadTerminado;
while not(t1.Finished and t2.Finished) do
CheckSynchronize;
try
except
on E: Exception do
Writeln(E.ClassName, ': ', E.Message);
end;
finally
Informador.Free;
Writeln;
Writeln('Terminado. Presione ENTER para salir');
Readln;
end;
end.