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.