Please break my program!!!!

Hi folks,

I'm trying to get an application of mine to deadlock. It always used to
work fine under Delphi 2, but it seems that the VCL code executed in
TThread.WaitFor has been beefed up a bit.

Essentially, what I want to do in the application below is to get things
to happen in the following order:

1. User starts prime thread.
2. User tries to quit app, and says "Yes, I'd like to quit anyway".
3. Main application thread goes to sleep (See line C in PrimeForm.pas).
4. Prime calculation thread eventually gets to the end of execution and
calls Synchronise. (Aided by modifications to lines A and B in
PrimeThread.pas).
5. Main application thread wakes up from sleep and calls WaitFor.

According to the VCL help, this should cause a deadlock. I seem to
remember being able to do this under D2. I'm currently using D4, and
instead of deadlocking, the WaitFor call does not block the main thread,
resulting in normal program termination.

Has this part of the VCL been changed between D2 and D4??

(source follows).

MH.

-------------------------------------------------------------------

unit PrimeForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs,
  StdCtrls, PrimeThread;

const
  WM_THREAD_COMPLETE = WM_APP + 5437; { Just a magic number }

type
  TPrimeFrm = class(TForm)
    NumEdit: TEdit;
    SpawnButton: TButton;
    ResultsMemo: TMemo;
    procedure SpawnButtonClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  private
    { Private declarations }
    FThread:TPrimeThrd;
    procedure HandleThreadCompletion(var Message:TMessage); message
WM_THREAD_COMPLETE;
  public
    { Public declarations }
  end;

var
  PrimeFrm: TPrimeFrm;

implementation

{$R *.DFM}

procedure TPrimeFrm.HandleThreadCompletion(var Message:TMessage);
begin
  if Assigned(FThread) then
  begin
    FThread.WaitFor;
    FThread.Free;
    FThread := nil;
  end;
end;

procedure TPrimeFrm.SpawnButtonClick(Sender: TObject);

begin
  if not Assigned(FThread) then
  begin
    FThread:=TPrimeThrd.Create(True);
    FThread.FreeOnTerminate:=false;
    try
      with FThread do
      begin
        TestNumber:=StrToInt(NumEdit.Text);
        Resume;
      end;
    except on EConvertError do
      begin
        FThread.Free;
        FThread:=nil;
        ShowMessage('That is not a valid number!');
      end;
    end;
  end;
end;

procedure TPrimeFrm.FormCloseQuery(Sender: TObject; var CanClose:
Boolean);
begin
  CanClose := true;
  if Assigned(FThread) then
  begin
    if MessageDlg('Threads active. Do you still want to quit?',
      mtWarning,[mbYes,mbNo],0) = mrNo then
      CanClose := false;
  end;
  Sleep(50000); {Line C}
  if CanClose then
  begin
    if Assigned(FThread) then
    begin
      FThread.Terminate;
      FThread.WaitFor;
      FThread.Free;
      FThread := nil;
    end;
  end;
end;

end.

-------------------------------------------------------------------

unit PrimeThread;

interface

uses
  Classes;

type
  TPrimeThrd = class(TThread)
  private
    FTestNumber:integer;
    FResultString:string;
  protected
    function IsPrime:boolean;
    procedure UpdateResults;
    procedure Execute; override;
  public
    property TestNumber:integer write FTestNumber;
  end;

implementation

uses SysUtils,Dialogs,PrimeForm,Windows;

procedure TPrimeThrd.UpdateResults;
begin
  PrimeFrm.ResultsMemo.Lines.Add(FResultString);
end;

function TPrimeThrd.IsPrime:boolean;

var
  iter:integer;

begin
  result:=true;
  if FTestNumber<0 then
  begin
    result:=false;
    exit;
  end;
  if FTestNumber<=2 then
    exit;
  iter:=2;
  while (iter < FTestNumber) {and (not terminated)} do {Line A}
  begin
    if (FTestNumber mod iter)=0 then
    begin
      result:=false;
      {exit;}
    end;
    Inc(iter);
  end;
end;

procedure TPrimeThrd.Execute;
begin
  if IsPrime then
    FResultString:=IntToStr(FTestNumber)+' is prime.'
  else
    FResultString:=IntToStr(FTestNumber)+' is not prime.';
  if {not Terminated}true then {Line B}
  begin
    Synchronize(UpdateResults);
    PostMessage(PrimeFrm.Handle,WM_THREAD_COMPLETE,0,0);
  end;
end;

end.

--
Martin Harvey. mar...@pergolesi.demon.co.uk
     http://www.pergolesi.demon.co.uk