在Delphi中,TDataSet是否线程安全?

14

我希望能够在独立的线程中异步地打开TDataSet,以便主VCL线程可以继续运行,直到完成后再从该TDataSet中读取。我进行了一些实验,并遇到了一些非常奇怪的情况,所以我想知道是否有人之前做过这个。

我看过一些示例应用程序,其中一个TDataSet在单独的线程中创建,然后它被打开并且数据从它中读取,但是这全部都是在单独的线程中完成的。我想知道在其他线程打开数据源后,从主VCL线程读取TDataSet是否安全。

我在Delphi 7中进行Win32编程,使用来自DAC for MySQL的TmySQLQuery作为我的TDataSet派生类。

6个回答

5
只要您只想在其自己的线程中使用数据集,您可以使用synchronize与主线程进行通信,以进行任何VCL/UI更新,就像使用任何其他组件一样。
或者,更好的方法是,您可以使用自己的消息系统实现主线程和工作线程之间的通信。
在这里查看Hallvard关于线程的解决方案:
http://hallvards.blogspot.com/2008/03/tdm6-knitting-your-own-threads.html
或者这个:
http://dn.codegear.com/article/22411
有关synchronize及其效率低下的一些解释,请参见此处:
http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/Ch3.html

我注意到从OmniThreadLibrary的FAQ(上面的链接)中得知它仅支持Delphi 2007和2009。有人在D7上使用过吗? - Liron Yahdav

4

我曾看到其他TDataSet实现方式中这样做过,比如Asta组件。它们会联系服务器,立即返回,然后在数据加载完毕后触发一个事件。

不过,我认为这很大程度上取决于组件本身。例如,那些相同的Asta组件不能从除主VCL线程以外的任何地方以同步方式打开。

所以简而言之,我认为这不是TDataSet本身的限制,而是某种特定实现的限制,而且我无法访问你提到的组件。


3

在多个线程之间使用相同的TDataSet时需要记住一件事情,即您只能在任何给定时间读取当前记录。因此,如果您在一个线程中读取记录,然后另一个线程调用Next,那么就会出现问题。


2

同时记得该线程可能需要自己的数据库连接。我认为这里需要一个多线程的“缓存”对象来将数据从线程中加载到(只写),然后从主VCL线程中只读。在读取之前,使用某种同步方法来确保你不会在写入时也读取,或者在读取时也写入,或者将所有内容加载到内存文件中,并编写同步方法告诉主应用程序在哪里停止读取。

我已经采用过上述方法几次,具体取决于预期记录数(和数据集的大小),我甚至将其转换为本地系统上的物理磁盘文件。它非常有效。


1

我已经完成了多线程数据访问,但这并不是一件容易的事情:

1)你需要为每个线程创建一个会话。

2)对于那个TDataSet实例所做的所有操作都必须在创建它的线程上下文中完成。如果你想在其上放置例如db grid之类的东西,那就不容易了。

3)如果你想让主线程处理你的数据,直接的解决方案是将其移动到某种单独的容器中,例如Memory dataset。

4)你需要一些信号机制来通知主线程一旦你的数据检索完成。

...而异常处理也不容易...

但是:一旦成功,应用程序将会非常优雅!


0

大多数TDatasets不是线程安全的。我知道一个线程安全的是kbmMemtable。它还具有克隆数据集的能力,因此不会出现Jim McKeeth所解释的移动记录指针的问题。它们是你可以获得的最好的数据集之一(无论是购买还是免费)。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接