简体   繁体   English

在 Delphi 中,TDataSet 线程安全吗?

[英]In Delphi, is TDataSet thread safe?

I'd like to be able to open a TDataSet asynchronously in its own thread so that the main VCL thread can continue until that's done, and then have the main VCL thread read from that TDataSet afterwards.我希望能够在它自己的线程中异步打开一个 TDataSet,以便主 VCL 线程可以继续直到完成,然后从该 TDataSet 读取主 VCL 线程。 I've done some experimenting and have gotten into some very weird situations, so I'm wondering if anyone has done this before.我做了一些实验,遇到了一些非常奇怪的情况,所以我想知道以前是否有人这样做过。

I've seen some sample apps where a TDataSet is created in a separate thread, it's opened and then data is read from it, but that's all done in the separate thread.我见过一些示例应用程序,其中 TDataSet 在单独的线程中创建,它被打开,然后从中读取数据,但这都是在单独的线程中完成的。 I'm wondering if it's safe to read from the TDataSet from the main VCL thread after the other thread opens the data source.我想知道在另一个线程打开数据源后从主 VCL 线程读取 TDataSet 是否安全。

I'm doing Win32 programming in Delphi 7, using TmySQLQuery from DAC for MySQL as my TDataSet descendant.我正在 Delphi 7 中进行 Win32 编程,使用来自DAC for MySQL 的TmySQLQuery 作为我的 TDataSet 后代。

Provided you only want to use the dataset in its own thread, you can just use synchronize to communicate with the main thread for any VCL/UI update, like with any other component.假设您只想在自己的线程中使用数据集,您可以使用同步与主线程通信以进行任何 VCL/UI 更新,就像与任何其他组件一样。
Or, better, you can implement communication between the mainthread and worker threads with your own messaging system.或者,更好的是,您可以使用自己的消息传递系统实现主线程和工作线程之间的通信。

check Hallvard's solution for threading here:在此处检查 Hallvard 的线程解决方案:
http://hallvards.blogspot.com/2008/03/tdm6-knitting-your-own-threads.html http://hallvards.blogspot.com/2008/03/tdm6-knitting-your-own-threads.html

or this other one:或另一个:
http://dn.codegear.com/article/22411 http://dn.codegear.com/article/22411

for some explanation on synchronize and its inefficiencies:有关同步及其低效的一些解释:
http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/Ch3.html http://www.eonclash.com/Tutorials/Multithreading/MartinHarvey1.1/Ch3.html

I have seen it done with other implementations of TDataSet, namely in the Asta components.我已经看到它与 TDataSet 的其他实现一起完成,即在Asta组件中。 These would contact the server, return immediately, and then fire an event once the data had been loaded.这些将联系服务器,立即返回,然后在加载数据后触发一个事件。

However, I believe it depends very much on the component.但是,我相信这在很大程度上取决于组件。 For example, those same Asta components could not be opened in a synchronous manner from anything other than the main VCL thread.例如,除了主 VCL 线程之外,无法以同步方式打开那些相同的 Asta 组件。

So in short, I don't believe it is a limitation of TDataSet per se, but rather something that is implementation specific, and I don't have access to the components you've mentioned.简而言之,我不认为这是 TDataSet 本身的限制,而是特定于实现的东西,我无权访问您提到的组件。

One thing to keep in mind about using the same TDataSet between multiple threads is you can only read the current record at any given time.在多个线程之间使用相同的TDataSet 时要记住的一件事是您只能在任何给定时间读取当前记录。 So if you are reading the record in one thread and then the other thread calls Next then you are in trouble.因此,如果您在一个线程中读取记录,然后另一个线程调用Next,那么您就有麻烦了。

Also remember the thread will most likely need its own database connection.还要记住,线程很可能需要自己的数据库连接。 I believe what is needed here is a multi-threaded "holding" object to load the data from the thread into (write only) which is then read only from the main VCL thread.我相信这里需要的是一个多线程“保持”对象来将数据从线程加载到(只写)中,然后只能从主 VCL 线程读取。 Before reading use some sort of syncronization method to insure that your not reading the same moment your writing, or writing the same moment your reading, or load everything into a memory file and write a sync method to tell the main app where in the file to stop reading.在阅读之前使用某种同步方法来确保你不会在你写作的同时阅读,或者在你阅读的同时写作,或者将所有内容加载到内存文件中并编写一个同步方法来告诉主应用程序在文件中的位置停止阅读。

I have taken the last approach a few times, depdending on the number of expected records (and the size of the dataset) I have even taken this to a physical disk file on the local system.我已经多次采用最后一种方法,这取决于预期记录的数量(和数据集的大小),我什至将它带到了本地系统上的物理磁盘文件中。 It works quite well.它运作良好。

I've done multithreaded data access, and it's not straightforward:我已经做过多线程数据访问,它并不简单:

1) You need to create a session per thread. 1)您需要为每个线程创建一个会话。

2) Everything done to that TDataSet instance must be done in context of the thread where it was created. 2) 对该 TDataSet 实例所做的一切都必须在创建它的线程的上下文中完成。 That's not easy if you wanted to place eg a db grid on top of it.如果您想在它上面放置例如一个 db 网格,这并不容易。

3) If you want to let eg main thread play with your data, the straight-forward solution is to move it into a separate container of some kind,eg a Memory dataset. 3)如果您想让例如主线程处理您的数据,直接的解决方案是将其移动到某种单独的容器中,例如内存数据集。

4) You need some kind of signaling mechanism to notify main thread once your data retrieval is complete. 4)一旦数据检索完成,您需要某种信号机制来通知主线程。

...and exception handling isn't straightforward, either... ……而且异常处理也不是那么简单……

But: Once you've succeeded, the application will be really elegant !但是:一旦你成功了,应用程序将会非常优雅!

Most TDatasets are not thread safe.大多数 TDataset 不是线程安全的。 One that I know is thread safe is kbmMemtable .我知道线程安全的一个是kbmMemtable It also has the ability to clone a dataset so that the problem of moving the record pointer (as explained by Jim McKeeth) does occur.它还具有克隆数据集的能力,因此确实会出现移动记录指针的问题(如 Jim McKeeth 所解释)。 They're one of the best datasets you can get (bought or free).它们是您可以获得(购买或免费)的最佳数据集之一。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM