Async

Async is the simplest of high-level abstractions and is typically used for fire and forget scenarios. To create an Async task, call Parallel.Async.



When you call Parallel.Async, code is started in a new thread (indicated by the bold vertical line) and both main and background threads continue execution. At some time, background task completes execution and disappears.

See also demo 46_Async.

Example:

Parallel.Async(
  procedure
  begin
    MessageBeep($FFFFFFFF);
  end);

This simple program creates a background task with a sole purpose to make some noise from it. The task is coded as an anonymous method but you can also use a normal method or a normal procedure for the task code.

The Parallel class defines two Async overloads. The first accepts a parameter-less background task and an optional task configuration block and the second accepts a background task with an IOmniTask parameter and an optional task configuration block.

type
  TOmniTaskDelegate = reference to procedure(const task: IOmniTask);
 
  Parallel = class
    class procedure Async(task: TProc;
      taskConfig: IOmniTaskConfig = nil); overload;
    class procedure Async(task: TOmniTaskDelegate;
      taskConfig: IOmniTaskConfig = nil); overload;
    ...
  end;

The second form is useful if the background code needs access to the IOmniTask interface, for example to send messages to the owner or to execute code in the owner thread (typically that will be the main thread).

The example below uses Async task to fetch the contents of a web page (by calling a mysterious function HttpGet) and then uses Invoke to execute a code that logs the length of the result in the main thread.

Parallel.Async(
  procedure (const task: IOmniTask)
  var 
    page: string;
  begin
    HttpGet('otl.17slon.com', 80, 'tutorials.htm', page, '');
    task.Invoke(
      procedure
      begin
        lbLogAsync.Items.Add(Format('Async GET: %d ms; page length = %d', 
          [time, Length(page)]))
      end);
  end);

The same result could be achieved by sending a message from the background thread to the main thread. TaskConfig block is used to configure message handler.

const
  WM_RESULT = WM_USER;
 
procedure LogResult(const task: IOmniTaskControl; const msg: TOmniMessage);
begin
  lbLogAsync.Items.Add(Format('Async GET: %d ms; page length = %d', 
    [time, Length(page)]))
end;
 
Parallel.Async(
  procedure (const task: IOmniTask)
  var 
    page: string;
  begin
    HttpGet('otl.17slon.com', 80, 'tutorials.htm', page, '');
    task.Comm.Send(WM_RESULT, page);
  end,
  TaskConfig.OnMessage(WM_RESULT, LogResult)
);

Let me warn you that in cases where you want to return a result from a background task, Async abstraction is not the most appropriate. You would be better off by using a Future.

Handling Exceptions

If the background code raises unhandled exception, OmniThreadLibrary will catch this exception and re-raise it in the OnTerminated handler. This way the exception will travel from the background thread to the owner thread where it can be processed.

As the OnTerminated handler occurs at the unspecified moment when Windows are processing window messages, there is no good way to catch this message with a try..except block. The caller must install its own OnTerminated handler instead and handle exception there.

The following example uses OnTerminated handler to detach fatal exception from the task, log the exception details and destroy the exception object.

Parallel.Async(
  procedure
  begin
    Sleep(1000);
    raise Exception.Create('Exception in Async');
  end,
  Parallel.TaskConfig.OnTerminated(
    procedure (const task: IOmniTaskControl)
    var
      excp: Exception;
    begin
      if assigned(task.FatalException) then begin
        excp := task.DetachException;
        Log('Caught async exception %s:%s',[excp.ClassName, excp.Message]);
        FreeAndNil(excp);
      end;
    end
  ));

If you don't install a OnTerminated handler, exception will be handled by the application-level filter, which will by default cause a message box to appear.

See also demo 48_OtlParallelExceptions.

book/highlevel/async.txt · Last modified: 2012/11/14 11:54 by gabr
Recent changes RSS feed Debian Powered by PHP Valid XHTML 1.0 Valid CSS Driven by DokuWiki