Search code examples
delphiasynchronousdelphi-2010

Why is AsyncCall running in main thread?


I have a model object that runs long operations. I'm trying to run some of these operations in threads to keep the interface responsive, download 2 things at once, etc, but I want to hide these details from the interface code as much as possible. I'm trying to use the AsyncCall library, but having issues.

type EUpdaterAction = (auFoundCurrentVersion, auFoundUpdateVersion);

type
  TUpdater = class
  public
    procedure loadCurrentVersion();
    procedure notify(action: EUpdaterAction);
  end;

procedure TUpdater.loadCurrentVersion();
begin
  TAsyncCalls.Invoke(procedure 
  begin 
    Assert(Windows.GetCurrentThreadId() <> System.MainThreadID);
    //Really long code
    TAsyncCalls.VCLSync(procedure begin notify(auFoundCurrentVersion); end);
  end);
end;

The assertion fails. Do I need to do something to make it run in a separate thread, or does the first example shown with the library just not actually run in threads?


Solution

  • You need to call IAsyncCall.ForceDifferentThread to force the code to run in a different thread. In your example the interface that TAsyncCalls.Invoke() returns is released immediately because the function ends and releasing the IAsyncCall interface calls the Sync method. And because your task hasn't started yet, the Syncmethod will execute it in the same thread, unless the ForceDifferentThread method was called.

    TAsyncCalls.Invoke(procedure 
    begin 
      Assert(Windows.GetCurrentThreadId() <> System.MainThreadID);
      //Really long code
      TAsyncCalls.VCLSync(procedure begin notify(auFoundCurrentVersion); end);
    end).ForceDifferentThread; // <<<<<
    

    But is that really what you want? I guess you want to keep the thread alive after loadCurrentVersion() has exited. And for this AsyncCalls isn't the right tool.