【问题标题】:TDataset thread races with DBGridTDataset 线程与 DBGrid 竞争
【发布时间】:2014-01-11 15:52:15
【问题描述】:

我使 TDataset 后代异步,而不是主线程中的 sleepProcessMessages,它通过来自网络线程的事件来工作。因此,当 Recordset 准备就绪时,它会调用

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

它有效,但有时我会遇到问题:GetRecordOpen 从该线程调用,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 并在另一条记录中获得断言。

我不太明白DBGridTDataset 的工作原理(即使堆栈跟踪很大),但是这个线程竞争可以解决吗?

【问题讨论】:

  • 不允许同时从两个线程访问 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


【解决方案1】:

解决方案非常简单:由于 TDataset 的 FBuffers(来自 Data.DB)中的数据如果未初始化则填充为 0,因此可以通过将另一个标记字节添加到记录中并在 GetRecord 中分配不为 0 来通过 GetRecord 找到填充的 ActiveBuffer . 因此,如果 DBGrid 尝试读取未初始化的数据,我会检查 GetFieldData 中的标记,如果 0 结果为假并退出。由于 DBGrid 不止一次地将数据提取到相同的单元格,因此我仍然用正确的数据填充它。 这是一种解决方法,但它有效。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-03-09
    • 1970-01-01
    • 1970-01-01
    • 2016-10-12
    • 1970-01-01
    • 2021-06-04
    • 1970-01-01
    • 2010-11-21
    相关资源
    最近更新 更多