1

I'm using OmniThreadLibrary to implement a background pipleline for sending emails (refer to this SO question). I notice that after closing the application, it continues running in the background (seen in Windows Task Manager). That means that there is something wrong in my code in the way I implemented the OTL pipeline. Can you help me identify the trouble?

Code follows:

unit uEmailQueue;

interface

uses Classes, OtlCommon, OtlCollections, OtlParallel, Windows;

type
  TEmailServer = record
    SMTPHost: String;
    SMTPPort: Integer;
    SMTPUseSSL: Boolean;
    SMTPUserName: String;
    SMTPPassword: String;
    SMTPSenderName: String;
  end;

  TEmailMessage = record
    RecipientEmailAddr: String;
    EmailSubject: String;
    EmailMessage: String;
  end;

  TEmailQueue = class(TObject)
  private
    FEmailServer: TEmailServer;
    FPipeline: IOmniPipeline;
    procedure SendEmailStage(const input, output: IOmniBlockingCollection);
  public
    constructor Create;
    destructor Destroy; override;
    procedure SendEmail(AEmailMessage: TEmailMessage);
  end;

implementation

{ TEmailQueue }

procedure TEmailQueue.SendEmailStage(const input, output: IOmniBlockingCollection);
var
  mailmessage: TOmniValue;
begin
  for mailmessage in input do
  begin
    Beep(3700, 1500); // just some dummy code for now
  end;
end;

constructor TEmailQueue.Create;
begin
  FPipeline := Parallel.pipeline.Stage(SendEmailStage).Run;

end;

destructor TEmailQueue.Destroy;
begin

  inherited;
end;

procedure TEmailQueue.SendEmail(AEmailMessage: TEmailMessage);
begin
  FPipeline.input.Add(TOmniValue.FromRecord(AEmailMessage));

  // FPipeline.input.CompleteAdding;

  // FPipeline.WaitFor(INFINITE);

end;

end.

I initialize and call the above class like this:

In the application's main form's OnCreate event:

  FEmailQueue := TEmailQueue.Create;

A button on the main form has this in the OnClick event:

var
  em: TEmailMessage;
begin
  FEmailQueue.SendEmail(em);

later, I free the class like this in the main form's OnDestroy event:

  FEmailQueue.Free;
Community
  • 1
  • 1
Steve F
  • 1,527
  • 1
  • 29
  • 55
  • `procedure TEmailQueue.SendEmail(AEmailMessage: TEmailMessage);` I bet that is not efficient, I think you better make A EmailMessage either into a const-parameter or into a var-parameter. – Arioch 'The Jun 15 '15 at 15:29
  • @Arioch'The Probably. If it was made const, then would it (also) prevent creating duplicate strings in memory (like var), and thus be faster? – Steve F Jun 16 '15 at 11:53
  • No, strings (except TurboPascal's ShortString[nnn] type and except MS-COM WideString type) like interfaces and dyn-arrays are ref-counted types, so strings themselves should not be copied when copying `TEmailMessage` – Arioch 'The Jun 16 '15 at 12:10
  • OTOH, post-XE1 Delphi is broken w.r.t. strings, so I would not be overly surprised if const'ing the parameter would save a something more than merely copying pointers and calling few Atomic-Increments http://kazav.blogspot.ru/2014/01/delphi-2.html – Arioch 'The Jun 16 '15 at 12:20

1 Answers1

3

You should call FPipeline.input.CompleteAdding from TEmailQueue.Destroy. Otherwise, SendEmailStage will never stop.

TLama
  • 75,147
  • 17
  • 214
  • 392
gabr
  • 26,580
  • 9
  • 75
  • 141