type TPrimeFrm = class(TForm) { No change here until public declarations } public { Public declarations } StringSemaphore: THandle; { Now a semaphore instead of a critical section } property StringBuf: TStringList read FStringBuf write FStringBuf; end; procedure TPrimeFrm.StartBtnClick(Sender: TObject); begin if not FStringSectInit then begin StringSemaphore := CreateSemaphore(nil, 1, 1, SemName); { Now creating a semaphore instead of a critical section } FStringBuf := TStringList.Create; FStringSectInit := true; FPrimeThread := TPrimeThrd2.Create(true); SetThreadPriority(FPrimeThread.Handle, THREAD_PRIORITY_BELOW_NORMAL); try FPrimeThread.StartNum := StrToInt(StartNumEdit.Text); except on EConvertError do FPrimeThread.StartNum := 2; end; FPrimeThread.Resume; end; UpdateButtons; end; procedure TPrimeFrm.StopBtnClick(Sender: TObject); begin if FStringSectInit then begin with FPrimeThread do begin Terminate; WaitFor; Free; end; FPrimeThread := nil; FStringBuf.Free; FStringBuf := nil; CloseHandle(StringSemaphore); { Deleting semaphore } FStringSectInit := false; end; UpdateButtons; end; procedure TPrimeFrm.HandleNewData(var Message: TMessage); begin if FStringSectInit then {Not necessarily the case!} begin WaitForSingleObject(StringSemaphore, INFINITE); { New wait call } ResultMemo.Lines.Add(FStringBuf.Strings[0]); FStringBuf.Delete(0); ReleaseSemaphore(StringSemaphore, 1, nil); { New release call } {Now trim the Result Memo.} if ResultMemo.Lines.Count > MaxMemoLines then ResultMemo.Lines.Delete(0); end; end; procedure TPrimeThrd2.Execute; var CurrentNum: integer; begin CurrentNum := FStartNum; while not Terminated do begin if IsPrime(CurrentNum) then begin WaitForSingleObject(PrimeFrm.StringSemaphore, INFINITE); { New wait call } PrimeFrm.StringBuf.Add(IntToStr(CurrentNum) + ' is prime.'); ReleaseSemaphore(PrimeFrm.StringSemaphore, 1, nil); { New release call } PostMessage(PrimeFrm.Handle, WM_DATA_IN_BUF, 0, 0); end; Inc(CurrentNum); end; end;