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?