Delphi, VCL, Threads & Async

I thought I would post my thoughts after being with Dataabstract for about two months. Yes, the learning curve IS very steep. What troubled me most, is the lack of info regarding real life use of threads and Async. Thats why I thought I post my experience for anyone interested in the future, and an issue I still need help solving.

The only thing that worked smoothly in the beginning was using MemDataTables in the main VCL thread. This worked, but did not satisfy me and resulted in locking of the GUI and VCL thread. So, I ventured into using threads and this is where all my headache started. Simply calling MemDataTables.Open in a thread in Delphi wrecked havoc in my app with a multitude of VCL components connected to them. Especially DBGrid and DBMemo was components that gave me most headache. So, after reading further in this forum, I saw that calling Open() on a ClonedSource should be thread safe. Ok, I changed my thread routines a bit, and implemented this. I have to agree that it helped a bit, but now I could not use DBMemo at all. I kept getting errors about the limit of DBMemo being exceeded.

Then I tried to ask a question about Async operations here on the forum and got som info on how to do this. So I implemented this and this also seamed to work for a little while. Not for long though! I started getting GUI freezes and AV that resulted in my app crashed and burned.

At the brink of giving up, I desperately searched this forum for information, and found a thread that recommended to disconnected the Datasource (setting it to nil), then load data, and then connected it again. Actually, I did tried setting Enabled to false for the DataSource, but that did not help. So, I set the Datasource.Datatable to nil, loaded data in a thread, and assigned the Datasource in the OnThreadTerminate procedure.

Voila!!! It worked. I now have a thread loading routine that works perfectly. So, it appears you have to completely disconnect the datasource for VCL components to prevent all these strange AV’s.

Another thing, I also tried to call RemoteDataAdapter.Fill() from the main thread, but that has som isses as well with connected VCL components. I guess by disconnecting the datasource, this would also help.

However, I would love to get the Async routines to work too. Lets say I disconnect the datasource from the MemDataTables and call BeginFill(). Once the callback arrives, how can I find out what DataTables was included in this request?? This is so I can assign the Datasource again. Can the array of TDADataTable that I pass to the BeginFill method be accessed in the IROAsyncRequest that is being passed to the callback function?

Over to ApplyUpdates. I have not had any issues calling this function from a Thread.

Over time, I would like to adopt only the Async approach. However, I need to find out how to get a hold of that array of Datatables in the callback functions. Can the UserData pointer be used? How to use it?

Well, I now have an operational applications that does not block my main thread and I’m quite happy with this. I just hoped someone would have written down what I have mentioned here before I started my Dataabstract adventure :slight_smile:

UserData can hold pointer to user’s object that can contain, for example, a list of TDADataTable or something else that can be useful for you.

back to your previous thread, it can be like

mylist := TList<TDAMemDatatable>.Create;
mylist.AddRange([table1,table2]);
RemoteDataAdapter.BeginFill(mycallback, mylist, [table1, table2]);
procedure TClientForm.mycallback(const aRequest: IROAsyncRequest);
var 
  mylist: TList<TDAMemDatatable>;
begin
  if (not aRequest.Cancelled) then begin
    RemoteDataAdapter.EndFill(aRequest);
    mylist := TList<TDAMemDatatable>(aRequest.UserData); 
    try
      ShowMessage( myList.Count.ToString +  ' tables were loaded');
    finally
       mylist.Free;
    end;
  end
  else 
    ShowMessage('Request was cancelled!');
end;

Thanks EvgenK. I’ll do some testing on on that approach.