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;
{ Ancillary procedures }
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 := 'Palindromic primes: ' + IntToStr(CurrentNumber) + ' and '
+ 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.