Jump to content
MJBComp

TTask.Run Finish Order???

Recommended Posts

I have a Task that starts and processes in the background. When the task is finished i want it to display a Dialog letting the user know the results.

 

Whats happening is the Task is "prematurely" displaying the Dialog before the Task has finished running. Below is my pseudo-code showing how things are lined up.

 

What is actually happening is as soon as the 'TransferEvents' procedure starts and the For Loop begins it immediately shows the dialog in the 'ShowDialogAfterTaskFinishes' before the loop is completed.

So i need a way to WAIT UNTIL the iteration of the FOR loop is finished and the Task is complete before processing the ShowDialogAfterTaskFinishes procedure.

 

 

I have even modified the code and tried doing  tasks: Array of ITask, and starting it that way and doing a WaitForAll but it still does the same thing.

 

 

procedure TfQBDailyInvoices.TransferEvent;
begin
  TTask.Run(procedure var x: Integer;
        begin
          for x := 0 to qInvoice.RecordCount - 1 do
          begin
            case ProcessInvoice of
              True: DidWorkorderTransfer := TRUE;
             False: DidWorkorderTransfer := FALSE;
            end;

            TThread.Synchronize(nil,
            procedure
            begin
               { Update User Interface }
               UpdateMainWindow;
            end);

            qInvoice.Next;
          end;
        end);
  { Event i want to fire AFTER the task is complete }
  ShowDialogAfterTaskFinishes;
end;

Share this post


Link to post

The code does exactly what you told it to:

1. Start a task in bg thread

2. Show dialog

 

If you want a final action, you should place it after the loop inside anon procedure

Share this post


Link to post
Posted (edited)

You have the call to ShowDialogAfterTaskFinishes() in the wrong place.

 

TTask runs asynchronously, but you are calling ShowDialogAfterTaskFinishes() immediately after the TTask object is created (and possibly before the TTask even begins to run).

 

You need to move the call to ShowDialogAfterTaskFinishes() inside of the TTask procedure itself, similar to what you have for the call to UpdateMainWindow(), eg:

procedure TfQBDailyInvoices.TransferEvent;
begin
  TTask.Run(
    procedure
    var
      x: Integer;
    begin
      try
        for x := 0 to qInvoice.RecordCount - 1 do
        begin
          DidWorkorderTransfer := ProcessInvoice;

          TThread.Synchronize(nil,
            procedure
            begin
              { Update User Interface }
              UpdateMainWindow;
            end
          );

          qInvoice.Next;
        end;
      finally
        TThread.Queue(nil, ShowDialogAfterTaskFinishes);
      end;
    end
  );
end;

Alternatively, you can use TThread.CreateAnonymousThread() instead, so you can use the TThread.OnTerminate event (which is Synchronize()'d with the main UI thread), eg:

procedure TfQBDailyInvoices.TransferEvent;
var
  Thread: TThread;
begin
  Thread := TThread.CreateAnonymousThread(
    procedure
    var
      x: Integer;
    begin
      for x := 0 to qInvoice.RecordCount - 1 do
      begin
        DidWorkorderTransfer := ProcessInvoice;

        TThread.Synchronize(nil,
          procedure
          begin
            { Update User Interface }
            UpdateMainWindow;
          end
        );

        qInvoice.Next;
      end;
    end
  );
  Thread.OnTerminate := TransferEventThreadTerminated;
  Thread.Start;
end;

procedure TfQBDailyInvoices.TransferEventThreadTerminated;
begin
  ShowDialogAfterTaskFinishes;
end;

:

 

Edited by Remy Lebeau

Share this post


Link to post

Fr0st.Brutal, thank you for your post. It pointed me in the right direction.

Remy Lebeau,  thank you for your post. Being able to visually see two different approaches really helped understand where to place the 'TransferEventThreadTerminated' procedure.  I had previously tried this very idea inside a Try...Finally...End loop but when i put the procedure inside the Finally section i didn't Queue the procedure i just put the procedure there and noticed that it fired before the thread was finished processing.  I will try this approach wrapping it into the Queue to see if it fires AFTER the thread process has completed.

Share this post


Link to post

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×