delphi - 关键部分能帮助解决这个问题吗?

标签 delphi thread-safety critical-section indy10

使用 Indy 10 TCP 命令处理程序,每次收到命令时,我都会向数据库中插入一行,然后从数据库中读取整个故事以更新字符串网格。

我正在使用 AnyDac 数据库组件,其文档显示“连接对象以及所有与其关联的对象(如 TADQuery、TADTransaction 等)在每个时刻都必须由单个线程使用”。

如果我“缓慢”发送 TCP 命令,就没有问题。如果我“快速”发送它们(当 AnyDac 仍然显示 SQL 游标时,我会收到异常 EDatabaseError“未找到字段” - 但它当然存在。

当我收到 TCP 命令时,我的代码使用 PostMEssage 向我的主窗体发送 UM_。

认为正在发生的是,主窗体正在从表中读取第一个 TCP 命令的所有行,而 TCP 命令处理程序正在插入新行作为第二个命令的结果 - 因此当我调用 ADQuery1.FieldByName() 时“找不到字段”。

这听起来像问题吗?

如果是这样,我该如何预防呢?可以使用关键部分(在哪里,主线程?)?或者还有其他办法吗?


[更新]我刚刚意识到 - 这不可能是线程问题(我认为)。当我收到 TCP 命令时,我使用 PostMessage() 向主窗体发送 UM_。因此,无论 TCP 命令来得有多快,我的主窗体一次只能通过其消息队列处理一个 UM_。 TCP 命令处理程序只是发送该消息的一行 - 没有 d/b 访问。

但是 - 我不明白的是,如果在 TCP 命令之间留出“一段时间”,一切都很好,但是如果我“快速”发送它们,那么我会收到异常,说该行中没有这样的字段表。


[更新] 事实上,我终于解决了这个问题,问题是使用更新速度相当慢的 TStringGrid。有多种方法可以使其更快,但我决定将其转换为 TDbGrid,它的更新速度非常快。

最佳答案

听起来您正在从后台线程中运行的 TCP 命令处理程序更新 AnyDac 数据库,并从主线程读取 AnyDac 数据库。由于 AnyDac 表示他们不支持多线程访问,因此这会产生问题。

一种选择是尝试让所有参与线程排队并等待访问 AnyDac 数据库。这违背了首先使用多个线程的目标 - 如果您要做的只是让它们排队并按顺序执行,为什么要使用多个线程呢?添加互斥锁(如临界区)会增加产生死锁情况的机会,尤其如果您计划在应用程序的重绘逻辑中获取该锁。您绝对不希望在重绘逻辑中锁定。

另一种方法是将数据库更新移至主线程中。执行此操作仍涉及一些线程同步,但责任在于后台线程,而不是主线程。

将数据库更新移至主线程的一种相对简单的方法是让 TCP 命令处理程序将自定义 UM_ 消息发布到主窗口(正如您已经在做的那样) 并附加数据到消息。消息处理程序从消息中获取数据,使用数据更新数据库,并处理附加到消息的数据。

通过这种方法,对 AnyDac 数据库对象的所有访问都发生在主线程中,因此不存在多线程问题。除非有人做了一些愚蠢的事情,例如在重绘周期中调用 Application.ProcessMessages,否则这应该可以解决重绘期间发生的数据库更新的任何问题。

关于delphi - 关键部分能帮助解决这个问题吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12832016/

相关文章:

android - delphi xe7 Mobile android中从右到左的语言

java - 检测调用者并识别线程

C - 无法将线程传递到具有特定票号的关键部分

ios - 什么是控制对存储服务器调用结果的属性的访问的正确方法?

delphi - 在 DDE 事件之后如何将窗口置于前面?

windows - 我应该在 Firemonkey 中使用 TMainMenu 来同时支持 Windows 和 OS-X 吗?

Delphi XE3 indy tbytes 和 tidbytes 之间的兼容性问题

multithreading - 防止Tomcat中的线程阻塞

java - 是否可以在少数线程但不是所有线程之间共享变量?

winapi - InitializeCriticalSectionAndSpinCount,是否有默认的旋转计数?