【发布时间】:2014-01-11 15:52:15
【问题描述】:
我使 TDataset 后代异步,而不是主线程中的 sleep 或 ProcessMessages,它通过来自网络线程的事件来工作。因此,当 Recordset 准备就绪时,它会调用
procedure TMySqlQuery.OrdinalOnDataReady(Sender: TObject);
begin
AddToLog('OrdinalOnDataReady');
FDataAvailable := true; // used in IsCursorOpen
inherited Open;
if Assigned(FParentOnDataReady) then
FParentOnDataReady(self);
end;
它有效,但有时我会遇到问题:GetRecord 由 Open 从该线程调用,DBGrid 的GetFieldData 由 DBGrid 的 DrawCells 从 Form 的 ProcessMessages 从主线程调用。通过记录我看到的两个函数
[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 | ........
当 ActiveBuffer 列数据为零时断言中断,我可以看到 DBGrid 尝试读取高于GetRecord 的行,读取到自己的内部 FBuffers。例如,如果断言在GetFieldData 第 3 行触发 - FBuffers 从 Recordset 中可用的总共 36 行中填充到第 2 行。当我使用 F8 逐步调试 GetRecord 时,没有错误,但我按 F9 并在另一条记录中获得断言。
我不太明白DBGrid 与TDataset 的工作原理(即使堆栈跟踪很大),但是这个线程竞争可以解决吗?
【问题讨论】:
-
不允许同时从两个线程访问 TDataSet。 TDataSet 不是线程安全的。
-
Joanna Carter 有很多关于 TDataSet 内部的文章。也许你仍然可以在某个地方找到它们....我记得我在 Delphi 5 中使用 TDbf 的经验,db-aware 控件只关心缓冲区的数量,因此,例如,如果你报告你有 10 个缓冲区计数 -控制是免费阅读它们。如果您的缓冲区还没有准备好 - 那么不要报告您有十个缓冲区。
-
@Arioch'The - Joannas 的文章在哪里?
-
@Branko 我会引用自己的话:也许你仍然可以在某个地方找到它们......在她厌倦了 EMBT 态度之前,它们就在她的网站上,Joanna Carter Consulting
-
stackoverflow.com/questions/78475/… 有消息说它是可能的(倒数第二个),没有带有“2”字样的详细信息)对该 TDataSet 实例所做的一切都必须在创建它的线程的上下文中完成. 如果你想在上面放置一个数据库网格,这并不容易。”实际上我遇到了 DBGrid 的问题并且想知道解决方案。
标签: multithreading delphi tdataset