В последнее время я исследую возможности выполнения параллельных и асинхронных операций в Delphi. В качестве одного из результатов родился класс TAwaitable. Код нарочито простой. С одной стороны хочется продемонстрировать идею, хотя она в целом очевидна, с другой стороны — получить свою порцию конструктивной критики. Я довольно мало сталкивался с многопоточностью в Delphi, так что будет здорово, если кто-то укажет на недочеты в реализации, если они есть.

Собственно, для большей наглядности сначала пример использования, а затем код самого класса.

procedure TForm1.Button1Click(Sender: TObject);
var
  WaitFor2, WaitFor3: IAwaitable<Integer>;
  Log: string;
begin
  Memo1.Lines.Add(DateTimeToStr(Now) + ' Start testing...');

  WaitFor2 := TAwaitable<Integer>.Create(
    function : Integer begin
      Sleep(2000);
      Result := 2;
    end);

  WaitFor3 := TAwaitable<Integer>.Create(
    function : Integer begin
      Sleep(3000);
      Result := 3;
    end);

  Memo1.Lines.Add(DateTimeToStr(Now) + ' One more action');
  Log := IntToStr(WaitFor2.Value + WaitFor3.Value);
  Memo1.Lines.Add(DateTimeToStr(Now) + ' And finally the result is... ' + Log);
  Log := IntToStr(WaitFor2.Value + WaitFor3.Value);
  Memo1.Lines.Add(DateTimeToStr(Now) + ' Cached result... ' + Log);
end;

Здесь запускаются в параллельное выполнение две функции. Одна выполняется 2 секунды, другая — 3. И в одном случае результат вычислений — 2, а в другом соответственно — 3. В качестве итога нам нужна сумма двух этих значений. Последовательное вычисление заняло бы, очевидно, 5 секунд. Но данный код выполняется за 3 секунды, благодаря тому, что он выполняется параллельно.

19.11.2013 23:33:04 Start testing...
19.11.2013 23:33:04 One more action
19.11.2013 23:33:07 And finally the result is... 5
19.11.2013 23:33:07 Cached result... 5

Повторное обращение к значению TAwaitable.Value выполняется быстрее, так как вычисления уже завершены.

Код самого класса довольно прост.

unit Awaitable;

interface

uses
  System.Classes;

type
  TAwaitableProc<T> = reference to function : T;

  IAwaitable<T> = interface
    function Value: T;
  end;

  TAwaitable<T> = class(TInterfacedObject, IAwaitable<T>)
  private
    FThread: TThread;
    FValue: T;
  public
    constructor Create(AwaitableProc: TAwaitableProc<T>); reintroduce;
    destructor Destroy; override;

    function Value: T;
  end;

implementation

{ TAwaitable<T> }

constructor TAwaitable<T>.Create(AwaitableProc: TAwaitableProc<T>);
begin
  inherited Create;

  FThread := TThread.CreateAnonymousThread(
    procedure begin
      FValue := AwaitableProc;
    end);

  FThread.FreeOnTerminate := False;
  FThread.Start;
end;

destructor TAwaitable<T>.Destroy;
begin
  FThread.Free;
  inherited;
end;

function TAwaitable<T>.Value: T;
begin
  FThread.WaitFor;
  Result := FValue;
end;

end.

Ну вот как-то так. Этот класс есть куда функционально развивать, но пока не хочется заходить слишком далеко.

update
День не прошел зря, я понял свой недочет. Вместо критических секций лучше использовать уже имеющийся в классе TThread метод WaitFor. Поэтому я немного изменил код.