1

In a program which uses the OmniThread library to create a parallel task, when I try to access a parameter in the parallel task, the code following after the parameter access is not executed, so obviously the task is aborted:

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

  OtlComm, OtlTask, OtlTaskControl, OtlEventMonitor;

type
  TForm1 = class(TForm)
    btnStartOTLTask: TButton;
    OTLMonitor: TOmniEventMonitor;
    procedure btnStartOTLTaskClick(Sender: TObject);
    procedure OTLMonitorTaskMessage(const task: IOmniTaskControl; const msg:
        TOmniMessage);
  private
    { Private-Deklarationen }
    FTestTask: IOmniTaskControl;
  public
    { Public-Deklarationen }
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

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

procedure TestParameters(const ATask: IOmniTask);
var
  test: Integer;
begin
  ATask.Comm.Send(16); // does execute
  test := ATask.Param['From']; // ?? <<<===========================
  ATask.Comm.Send(17); // does NOT execute!
end;

procedure TForm1.btnStartOTLTaskClick(Sender: TObject);
begin
  if not Assigned(FTestTask) then // prevent multiple tasks
    FTestTask := CreateTask(TestParameters, 'TestParameters')
                   .MonitorWith(OTLMonitor)
                   .SetParameters(['From', 0, 'To', 99])
                   .Run
  else
    MessageDlg('Task is already running!', mtInformation, [mbOK], 0);
end;

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

So what's wrong with accessing the parameter 'From'?

user1580348
  • 5,721
  • 4
  • 43
  • 105
  • 1
    Instead of just setting the caption in your OnTaskMessage event handler, put the message into a memo or similar for debugging. When debugging, put a breakpoint in TestParameters and step through all lines. Testing for Assigned(FTestTask) without having a call to FTestTask.Terminate and FTestTask := nil seems strange. – LU RD Sep 22 '14 at 21:02
  • @LURD I've done as you said and stepped through TestParameters: In the line with parameter access I got an exception `TOmniValueContainer.Getltem: Parameter From does not exist`. So obviously there is something wrong with `SetParameters`, which BTW follows exactly how it is explained in the OmniThread documentation. – user1580348 Sep 22 '14 at 21:45
  • It seems that it works only in this way: `test := ATask.Param.ByName('From');` AND instead of `SetParameters` with the open array using multiple calls of `.SetParameter('From', 1).SetParameter('To', 99)` etc. – user1580348 Sep 22 '14 at 21:58
  • This is a bug in current implementation of SetParameter. The underlying storage has changed when I added array support to TOmniValue and SetParameters was not modified to reflect that change. I'll fix this ASAP. – gabr Sep 23 '14 at 07:24
  • @gabr Thanks. Can you please tell me how can I pass (and then access) a TRect in SetParameter? `.SetParameter('FormRect', Self.ClientRect)` is not supported. – user1580348 Sep 23 '14 at 08:09
  • Please make a new question and I'll answer there. That way other users will be able to find this answer. – gabr Sep 23 '14 at 08:37
  • This is now fixed in the SVN. Thanks for the report! – gabr Sep 23 '14 at 08:57
  • @gabr The new question is here: http://stackoverflow.com/questions/25991056/omnithread-how-to-pass-a-trect-in-setparameter – user1580348 Sep 23 '14 at 09:06

1 Answers1

2

I've found a workaround:

procedure TestParameters(const ATask: IOmniTask);
begin
  // this does work:
  ATask.Comm.Send(ATask.Param.ByName('From'));
  ATask.Comm.Send(ATask.Param.ByName('To'));

  // ALSO this does work:
  ATask.Comm.Send(ATask.Param['From']);
  ATask.Comm.Send(ATask.Param['To']);
end;

procedure TForm1.btnStartOTLTaskClick(Sender: TObject);
begin
  if not Assigned(FTestTask) then // prevent multiple tasks
    FTestTask := CreateTask(TestParameters, 'TestParameters')
                   .MonitorWith(OTLMonitor)
                   // SetParameters does not work:
                   //.SetParameters(['From', 1, 'To', 99])
                   // this does work:
                   .SetParameter('From', 1)
                   .SetParameter('To', 99)
                   .Run
  else
    MessageDlg('Task is already running!', mtInformation, [mbOK], 0);
end;

procedure TForm1.OTLMonitorTaskMessage(const task: IOmniTaskControl; const msg: TOmniMessage);
begin
  Memo1.Lines.Add(IntToStr(msg.MsgID));
end;

procedure TForm1.OTLMonitorTaskTerminated(const task: IOmniTaskControl);
begin
  FTestTask := nil;
  Memo1.Lines.Add('Task terminated');
end;
user1580348
  • 5,721
  • 4
  • 43
  • 105