在Delphi中,TDataSet线程安全吗?
我希望能够在其自己的线程中异步打开TDataSet,以便主VCL线程可以继续执行直到完成,然后再从该TDataSet中读取主VCL线程。我已经做了一些实验,并陷入了一些非常奇怪的情况,所以我想知道以前是否有人这样做过。
我看过一些示例应用程序,其中在单独的线程中创建了TDataSet,将其打开,然后从中读取数据,但这都是在单独的线程中完成的。我想知道在其他线程打开数据源之后从VCL主线程读取TDataSet是否安全。
我正在Delphi 7中进行Win32编程,使用来自DAC for MySQL的TmySQLQuery作为我的TDataSet后代。
解决方案
回答
我已经看到它是通过TDataSet的其他实现完成的,即在Asta组件中。这些将联系服务器,立即返回,然后在加载数据后触发一个事件。
但是,我认为这在很大程度上取决于组件。例如,那些相同的Asta组件无法以同步方式从VCL主线程以外的任何其他对象打开。
简而言之,我不认为这本身就是对TDataSet的限制,而是某些特定于实现的东西,并且我无权访问我们提到的组件。
回答
在多个线程之间使用同一TDataSet时要记住的一件事是,我们只能在任何给定时间读取当前记录。因此,如果我们正在一个线程中读取记录,然后另一个线程调用Next,那么我们将遇到麻烦。
回答
还要记住,线程很可能需要其自己的数据库连接。我相信这里需要的是一个多线程"保持"对象,用于将线程中的数据加载到(仅写)中,然后再从主VCL线程中读取该对象。在阅读之前,请使用某种同步方法来确保我们不会在写作的同时阅读,或者在阅读的同时阅读,或者将所有内容加载到内存文件中并编写同步方法来告知主应用程序文件在何处停止阅读。
我已经采用了最后一种方法,这取决于预期的记录数(以及数据集的大小),我甚至已经将其用于本地系统上的物理磁盘文件。效果很好。
回答
如果只想在自己的线程中使用数据集,则可以使用sync与任何其他组件的VCL / UI更新的主线程进行通信。
或者,更好的是,我们可以使用自己的消息传递系统在主线程和工作线程之间实现通信。
在此处检查Hallvard的线程解决方案:
http://hallvards.blogspot.com/2008/03/tdm6-knitting-your-own-threads.html
或者另外一个:
http://dn.codegear.com/article/22411
有关同步及其效率低下的一些说明:
http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/Ch3.html
回答
我已经完成了多线程数据访问,这并不简单:
1)我们需要为每个线程创建一个会话。
2)必须在创建该TDataSet实例的线程的上下文中完成对该TDataSet实例的所有操作。如果我们想放置例如在其顶部的数据库网格。
3)如果我们想让主线程处理数据,直接的解决方案是将其移动到某种单独的容器中,例如内存数据集。
4)一旦数据检索完成,我们需要某种信令机制来通知主线程。
...而且异常处理也不是直接的...
但是:成功之后,该应用程序将非常优雅!
回答
大多数TDataset都不是线程安全的。我知道线程安全的一种是kbmMemtable。它还具有克隆数据集的功能,从而确实会发生移动记录指针的问题(如Jim McKeeth所述)。它们是我们可以获得(购买或者免费)的最佳数据集之一。