unit PrimeThreads;
 
interface
 
uses
 Windows, Classes, SysUtils, BoundedBuf, Forms;
 
type
 TIntRec = record
 Num: integer;
 end;
 PIntRec = ^TIntRec;
 
 TPrimeThread = class(TThread)
 private
 FBuffer: TBoundedBuffer;
 protected
 function IsPrime(TestNum: integer): boolean;
 public
 property Buffer: TBoundedBuffer read FBuffer write FBuffer;
 end;
 
 TForwardPrimeThread = class(TPrimeThread)
 private
 protected
 procedure SendToBackThread(TestNum: integer);
 procedure Execute; override;
 end;
 
 TBackwardPrimeThread = class(TPrimeThread)
 private
 FDestSection: PRTLCriticalSection;
 FDestMsgNum: integer;
 FDestForm: TForm;
 FDestList: TStrings;
 protected
 function ReverseNumber(Input: integer): integer;
 function RecieveFromForwardThread(var TestNum: integer): boolean;
 procedure SendToVCLThread(CurrentNumber, ReversedNumber: integer);
 procedure Execute; override;
 public
 property DestSection: PRTLCriticalSection read FDestSection write FDestSection;
 property DestMsgNum: integer read FDestMsgNum write FDestMsgNum;
 property DestForm: TForm read FDestForm write FDestForm;
 property DestList: TStrings read FDestList write FDestList;
 end;
 
var
 ForwardThread: TForwardPrimeThread;
 BackwardThread: TBackwardPrimeThread;
 Buffer: TBoundedBuffer;
 
procedure StartThreads(Form: TForm;
 Section: PRTLCriticalSection;
 MsgNum: integer;
 List: TStrings);
procedure StopThreads;
 
implementation
 
const
 DefBufSize = 16;
 
{ Procedimientos auxiliares }
 
procedure StartThreads(Form: TForm;
 Section: PRTLCriticalSection;
 MsgNum: integer;
 List: TStrings);
begin
 ForwardThread := TForwardPrimeThread.Create(true);
 BackwardThread := TBackwardPrimeThread.Create(true);
 SetThreadPriority(ForwardThread.Handle, THREAD_PRIORITY_BELOW_NORMAL);
 SetThreadPriority(BackwardThread.Handle, THREAD_PRIORITY_BELOW_NORMAL);
 Buffer := TBoundedBuffer.Create;
 Buffer.Size := DefBufSize;
 ForwardThread.Buffer := Buffer;
 BackwardThread.Buffer := Buffer;
 with BackwardThread do
 begin
 DestForm := Form;
 DestSection := Section;
 DestMsgNum := MsgNum;
 DestList := List;
 end;
 ForwardThread.Resume;
 BackwardThread.Resume;
end;
 
procedure StopThreads;
begin
 ForwardThread.Terminate;
 BackwardThread.Terminate;
 Buffer.ResetState;
 ForwardThread.WaitFor;
 BackwardThread.WaitFor;
 Buffer.Free;
 ForwardThread.Free;
 BackwardThread.Free;
end;
 
{ TPrimeThread }
 
function TPrimeThread.IsPrime(TestNum: integer): boolean;
 
var
 iter: integer;
 
begin
 result := true;
 if TestNum < 0 then
 result := false;
 if TestNum <= 2 then
 exit;
 iter := 2;
 while (iter < TestNum) and (not terminated) do {Line A}
 begin
 if (TestNum mod iter) = 0 then
 begin
 result := false;
 exit;
 end;
 Inc(iter);
 end;
end;
 
{ TForwardPrimeThread }
 
procedure TForwardPrimeThread.SendToBackThread(TestNum: integer);
 
var
 NewRec: PIntRec;
 
begin
 New(NewRec);
 NewRec.Num := TestNum;
 if not Buffer.PutItem(NewRec) then Dispose(NewRec);
end;
 
procedure TForwardPrimeThread.Execute;
 
var
 CurrentNumber: integer;
 
begin
 CurrentNumber := 2;
 while not Terminated do
 begin
 if IsPrime(CurrentNumber) then
 SendToBackThread(CurrentNumber);
 Inc(CurrentNumber);
 end;
end;
 
{ TBackwardPrimeThread }
 
function TBackwardPrimeThread.RecieveFromForwardThread(var TestNum: integer): boolean;
 
var
 NewRec: PIntRec;
 
begin
 NewRec := Buffer.GetItem;
 Result := Assigned(NewRec);
 if Result then TestNum := NewRec^.Num;
end;
 
procedure TBackwardPrimeThread.SendToVCLThread(CurrentNumber, ReversedNumber: integer);
 
var
 Msg: string;
 
begin
 Msg := 'Primos palndromos: ' + IntToStr(CurrentNumber) + ' y '
 + IntToStr(ReversedNumber);
 EnterCriticalSection(FDestSection^);
 DestList.Add(Msg);
 LeaveCriticalSection(FDestSection^);
 PostMessage(DestForm.Handle, DestMsgNum, 0, 0);
end;
 
function TBackwardPrimeThread.ReverseNumber(Input: integer): integer;
 
var
 InStr, OutStr: string;
 Len, Iter: integer;
 
begin
 Input := Abs(Input);
 InStr := IntToStr(Input);
 OutStr := '';
 Len := Length(InStr);
 for Iter := Len downto 1 do
 OutStr := OutStr + InStr[Iter];
 try
 Result := StrToInt(OutStr);
 except
 on EConvertError do Result := Input;
 end;
end;
 
procedure TBackwardPrimeThread.Execute;
 
var
 CurrentNumber,
 ReversedNumber: integer;
 
begin
 while not Terminated do
 begin
 if RecieveFromForwardThread(CurrentNumber) then
 begin
 ReversedNumber := ReverseNumber(CurrentNumber);
 if IsPrime(ReversedNumber) then
 SendToVCLThread(CurrentNumber, ReversedNumber);
 end;
 end;
end;
 
end.