0

This is a sample code for a stopwatch I have implemented as a separate thread with the OmniThread library.

This is my question: Do I have to terminate and nil the task when the form closes or will it be destroyed automatically when the form closes?

uses
  System.SysUtils, System.Classes,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls,

  OtlComm, OtlTask, OtlTaskControl, OtlEventMonitor;

type
  TForm1 = class(TForm)
    OTLMonitor: TOmniEventMonitor;
    btnStartClock: TButton;
    btnStopClock: TButton;
    procedure btnStartClockClick(Sender: TObject);
    procedure btnStopClockClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure OTLMonitorTaskMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
    procedure OTLMonitorTaskTerminated(const task: IOmniTaskControl);
  private
    { Private-Deklarationen }
    FClockTask: IOmniTaskControl;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

{ Place a TOmniEventMonitor component on the form,
  name it OTLMonitor,
  implement the OnTaskTerminated event-handler: OTLMonitorTaskTerminated
  and implement the OnTaskmessage event-handler: OTLMonitorTaskMessage }

var
  StopMessage: string;

procedure ShowElapsedSeconds(const ATask: IOmniTask);
var
  ElapsedSeconds: Integer;
begin
  ElapsedSeconds := 0;
  while not ATask.Terminated do
  begin
    // stop after 10 seconds:
    if ElapsedSeconds >= 10 then BREAK;

    Inc(ElapsedSeconds);
    ATask.Comm.Send(ElapsedSeconds);
    Sleep(1000);
  end;
end;

procedure TForm1.OTLMonitorTaskMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
begin
  // show elapsed seconds:
  Self.Caption := IntToStr(msg.MsgID);
end;

procedure TForm1.OTLMonitorTaskTerminated(const task: IOmniTaskControl);
begin
  FClockTask := nil;
  Self.Caption := StopMessage;
end;

procedure TForm1.btnStartClockClick(Sender: TObject);
begin
  if not Assigned(FClockTask) then // prevent multiple clock-tasks
  begin
    StopMessage := 'Automatically stopped after 10 seconds';
    FClockTask := CreateTask(ShowElapsedSeconds, 'ShowElapsedSeconds').MonitorWith(OTLMonitor).Run;
  end
  else
  begin
    MessageDlg('Clock is already running!', mtInformation, [mbOK], 0);
    { Nice: The clock continues to run even while this message dialog is displayed! }
  end;
end;

procedure TForm1.btnStopClockClick(Sender: TObject);
begin
  if Assigned(FClockTask) then
  begin
    StopMessage := 'Stopped by the user';
    FClockTask.Terminate;
    FClockTask := nil;
  end
  else
    MessageDlg('Clock is not running!', mtInformation, [mbOK], 0);
end;

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  if Assigned(FClockTask) then
  begin
    { Do I need to terminate and nil the clock-task here?
      Or will it be destroyed autmatically when the form closes? }
  end;
end;
user1580348
  • 5,721
  • 4
  • 43
  • 105
  • `OTLMonitorTaskTerminated` is never referenced. `FClockTask` leaves scope when its owning object is destroyed. Just like any other variable. – David Heffernan Sep 22 '14 at 11:56
  • @DavidHeffernan `OTLMonitorTaskTerminated` is an event handler of the `OTLMonitor` component placed on the form. It is triggered when the task terminates (either automatically after 10 seconds or by the user). I see nothing wrong here. What do you mean with "never referenced"? – user1580348 Sep 22 '14 at 12:02
  • Well, I cannot see the .dfm file. So from what I saw here, that method was never referenced. – David Heffernan Sep 22 '14 at 12:03
  • @DavidHeffernan I have complemented the instruction to implement the OTLMonitorTaskTerminated event handler. For the second point: So I don't have to explicitly terminate the task on FormClose? Thank you! – user1580348 Sep 22 '14 at 12:11
  • Well, depends on `FormClose` does. Does it destroy the form object or not. What close action are you using? – David Heffernan Sep 22 '14 at 12:11
  • @DavidHeffernan The default action: `caFree` – user1580348 Sep 22 '14 at 12:20
  • OK, in that case, `FClockTask` goes out of scope because the form object is destroyed, and I guess that does what you want right? – David Heffernan Sep 22 '14 at 12:28
  • @DavidHeffernan So this means that the OmniThread task thread is automatically destroyed when its owner form is destroyed? Can a thread be "owned" by a form? – user1580348 Sep 22 '14 at 12:35
  • I don't see any threads here. OTL is meant to insulate you from threads. If the task is running, are you allowed to finalise the task control? – David Heffernan Sep 22 '14 at 12:39
  • In Windows Task Manager, I can see that an additional thread is added to the process when I start the clock. – user1580348 Sep 22 '14 at 12:53
  • Yes, but threads are not your concern. What you need to know is whether or not you need to explicitly terminate the task. What do the docs say? – David Heffernan Sep 22 '14 at 14:13

1 Answers1

1

Primož Gabrijelčič, the author of "Parallel Programming with OmniThreadLibrary" writes:

"We should also handle the possibility of user closing the program by clicking the ‘X’ button while the background scanner is active. We must catch the OnFormCloseQuery event and tell the task to terminate.

procedure TfrmBackgroundFileSearchDemo.FormCloseQuery(Sender: TObject;
var CanClose: boolean);
begin
  if assigned(FScanTask) then
  begin
    FScanTask.Terminate;
    FScanTask := nil;
    CanClose := true;
  end;
end;"

This book is for sale at http://leanpub.com/omnithreadlibrary

user1580348
  • 5,721
  • 4
  • 43
  • 105