I made TDataset descendant asynchronous, instead of sleep or ProcessMessages in main thread it works by events from network thread. So when Recordset is ready it calls

procedure TMySqlQuery.OrdinalOnDataReady(Sender: TObject);
begin
  AddToLog('OrdinalOnDataReady');
  FDataAvailable := true; // used in IsCursorOpen
  inherited Open;
  if Assigned(FParentOnDataReady) then
      FParentOnDataReady(self);
end;

It works, but sometime I have issues with GetRecord by Open called from this thread and DBGrid's GetFieldData called from main thread by DBGrid's DrawCells from Form's ProcessMessages. By logging both functions I see

[17:10:39] RecordToBuffer row 0
[17:10:39] len = 17 buf : 
00 E0 10 C3 00 0A 00 00 00 F0 10 C3 00 0B 00 00   |  .ïœ.ï“.....ÿ€.ï“....
00   |  .
[17:10:40] RecordToBuffer row 1
[17:10:40] len = 17 buf : 
00 00 FF C3 00 25 00 00 00 10 11 C3 00 0B 00 00   |  ..ÿï“.%.....ï“....
00   |  .
[17:10:40] ActiveBuffer
[17:10:40] len = 17 buf : 
00 E0 10 C3 00 0A 00 00 00 F0 10 C3 00 0B 00 00   |  .ïœ.ï“.....ÿ€.ï“....
00   |  .
...
more ActiveBuffer
...
[17:10:40] ActiveBuffer
[17:10:40] len = 17 buf : 
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00   |  ................
00   |  .
[17:10:40] len = 8 buf : 
00 00 00 00 00 00 00 00   |  ........

and on break by assert when ActiveBuffer column data is nil I can see that DBGrid attempts to read row higher than GetRecord readed into own internal FBuffers. For example if assertion fired at GetFieldData row 3 - FBuffers filled up to row 2 from total 36 rows available in Recordset. When I debugging step by step GetRecord with F8 there is no errors utnil I press F9 and get assertion at another record.

I'm not quite understand how exactly DBGrid works with TDataset (even stack trace is huge), but can this thread races be solved?

有帮助吗?

解决方案

Solution was quite simple: since data in TDataset's FBuffers (from Data.DB) filled with 0 if not initialized it is possible to find filled ActiveBuffer by GetRecord or not by adding yet another marker byte into record and assigning not 0 in GetRecord. So if DBGrid attempts to read uninitialized data I checking marker in GetFieldData, if 0 result false and exit. Since DBGrid extracting data to same cells more than once I still have it filled with proper data. It is workaround but it works.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top