In Delphi, is TDataSet thread safe? - multithreading

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. 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. 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.
I'm doing Win32 programming in Delphi 7, using TmySQLQuery from DAC for MySQL as my TDataSet descendant.

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.
Or, better, you can implement communication between the mainthread and worker threads with your own messaging system.
check Hallvard's solution for threading here:
http://hallvards.blogspot.com/2008/03/tdm6-knitting-your-own-threads.html
or this other one:
http://dn.codegear.com/article/22411
for some explanation on synchronize and its inefficiencies:
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. 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.
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.

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. So if you are reading the record in one thread and then the other thread calls Next then you are in trouble.

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. 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.
2) Everything done to that TDataSet instance must be done in context of the thread where it was created. That's not easy if you wanted to place e.g. a db grid on top of it.
3) If you want to let e.g. main thread play with your data, the straight-forward solution is to move it into a separate container of some kind,e.g. a Memory dataset.
4) You need some kind of signaling mechanism to notify main thread once your data retrieval is complete.
...and exception handling isn't straightforward, either...
But: Once you've succeeded, the application will be really elegant !

Most TDatasets are not thread safe. One that I know is thread safe is 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. They're one of the best datasets you can get (bought or free).

Related

Delphi call TDBGrid.Datasource.Dataset.Refresh from a background thread [duplicate]

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. 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. 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.
I'm doing Win32 programming in Delphi 7, using TmySQLQuery from DAC for MySQL as my TDataSet descendant.
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.
Or, better, you can implement communication between the mainthread and worker threads with your own messaging system.
check Hallvard's solution for threading here:
http://hallvards.blogspot.com/2008/03/tdm6-knitting-your-own-threads.html
or this other one:
http://dn.codegear.com/article/22411
for some explanation on synchronize and its inefficiencies:
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. 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.
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.
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. So if you are reading the record in one thread and then the other thread calls Next then you are in trouble.
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. 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.
2) Everything done to that TDataSet instance must be done in context of the thread where it was created. That's not easy if you wanted to place e.g. a db grid on top of it.
3) If you want to let e.g. main thread play with your data, the straight-forward solution is to move it into a separate container of some kind,e.g. a Memory dataset.
4) You need some kind of signaling mechanism to notify main thread once your data retrieval is complete.
...and exception handling isn't straightforward, either...
But: Once you've succeeded, the application will be really elegant !
Most TDatasets are not thread safe. One that I know is thread safe is 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. They're one of the best datasets you can get (bought or free).

Interthread communication

The following question is about the unity game engine, but it could relate to any program trying to send data to a main thread, such as the UI thread.
I am processing some data on a separate thread (position data a read asyncrously from a socket). However, I need to act on this data on the main thread (a game object's transform can only be accessed from the main thread). The approach I have in mind is to create a thread-safe queue and follow the producer-consumer pattern. The thread would queue the position data and the main thread would deque the data and act on it. *Note: In Unity I do not have access to the System.Windows.Threading name space so I can not use Dispatcher. Also, it requires .Net 3.5 so I can't use the Collections.Concurrent name space either.
Is there a better approach?
If there isn't, what is the best way to inform the main thread when data is queued? It seems inefficient to poll, but I can't think of any way around it..
Thanks in advance.
That is a totally viable approach to threading. As you probably know, the alternative to polling found in computer hardware is the concept of interrupts.
How would you simulate interrupts in a multithreaded high-level computer program? Hard to say - your thread that changes would have to notify the UI thread "hey I'm ready", rather than the UI thread checking constantly. This requires some sort of message passing, really - it may not be feasible.
That being said, the typical game-design approach is the "game loop" that does, essentially, poll. So there is no shame in that game - you just have to make sure it doesn't murder your performance.
May be this question has an answer for you.
However, polling a queue is a cleaner solution IMHO, and not so costly if done right and there are tons of examples in the Internet.

Can you receive Events in a secondary thread in Delphi XE?

I would like to have three threads in a sample application.
Thread #1 (Main Thread) - User Interface/GUI
Thread #2 - Tied to a serial port device receiving data via events passing to a data queue.
Thread #3 - Activated when a queue entry is made, process data node, frees data object.
The goal is to
a) Prevent the loss of data when a button or the form is held by the mouse on the main form.
b) Quickly get the data from the event, stuff it in the queue, go back to sleep
c) Process data when we have it, otherwise sleep.
Can packages like AsyncoPro tie event handling to a non-main thread?
I've never done much with serial port event driven apps, most of what I've work with are polled and I want to do some testing.
You can definitely tie event handling to a non-main thread. What you can't do is tie screen updating to a non-main thread. The Windows API is not threadsafe, and so the Delphi VCL, which is built on top of the Windows API, isn't either. But your design is basically a good, workable idea; just remember to use the Synchronize or Queue methods of TThread to send any UI updates back to be executed on the main thread.
The easiest should be to define some user messages, then sent it from sub-threads to the main thread.
It's perfectly thread-safe, and even process-safe.
Use PostMessage() with the Handle of the main form. But don't broadcast this WM_USER+n message to the whole UI, because you could confuse some part of the VCL which defines its own custom messages.
If you want to copy some textual data accross threads or processes, you can see WM_COPY_DATA. In practice, this is very fast, faster than named pipes for small messages.
For User Interface, I discovered than a stateless implementation is sometimes a good idea. That is, you don't call-back the main thread via a Synchronize() call or a GDI message, but your main GUI thread has a timer which check a shared memory buffer for pending updates. This is how the web works, and in practice, it's pretty easy to work with: you don't have to write any callback, each thread is independent, do its own stuff, and refresh when necessary.
But of course, the solution depends on your exact project architecture.
For a simple but proven library, see AsyncCalls, working from Delphi 5 up to XE. For latest versions of the IDE (Delphi 2007 and later), take a look at OmniThreadLibrary. By using such libraries, you'll ensure that your software implementation won't break anywhere: it's very common for a multi-threaded application to work as expected most of the time, then, for unknown reasons, going into an endless loop. And, of course, it happens only on the customer side, not yours... If you don't want to spend hours debugging your program, just trust those proven libraries, which are known to be well designed and debugged.
Sure you can do this, one way or another. Not used Apro since D5 - the Apro I have does not work on my D2009, (unicode/string/ANSIstring issues), & I have my own serial classes. Most of the available serial components have the option of firing dataRx events on either the rx thread or the main GUI thread - obviously in your case you should select the rx thread, (Thread #2). Shove the rx data into some buffer class and push it onto a producer-consumer thread to (Thread #3). Process it there. If you need to do a GUI update from there, PostMessage the reference to the GUI thread and handle it in a user-defined message-handler procedure.
Done this sort of stuff loadsa times - it will work OK.
Rgds,
Martin

DB-connection in separate thread - what's the best way?

I am creating an app that accesses a database. On every database access, the app waits for the job to be finished.
To keep the UI responsive, I want to put all the database stuff in a separate thread.
Here is my idea:
The db-thread creates all database components it needs when it is created
Now the thread just sits there and waits for a command
If it receives a command, it performs the action and goes back to idle. During that time the main thread waits.
the db-thread lives as long as the app is running
Does this sound ok?
What's the best way to get the database results from the db-thread into the main thread?
I haven't done much with threads so far, therefore I'm wondering if the db-thread can create a query component out of which the main thread reads the results. Main thread and db thread will never access the query at the same time. Will this still cause problems?
What you are looking for is the standard data access technique, called asynchronous query execution. Some data access components implement this feature in an easy-to-use manner. At least dbGo (ADO) and AnyDAC implement that. Lets consider the dbGo.
The idea is simple - you call the convenient dataset methods, like a Open. The method launches required task in a background thread and immediately returns. When the task is completed, an appropriate event will be fired, notifying the application, that the task is finished.
The standard approach with the DB GUI applications and the Open method is the following (draft):
include eoAsyncExecute, eoAsyncFetch, eoAsyncFetchNonBlock into dataset ExecuteOptions;
disconnect TDataSource.DataSet from dataset;
set dataset OnFetchComplete to a proc P;
show "Hello ! We do the hard work to process your requests. Please wait ..." dialog;
call the dataset Open method;
when the query execution will be finished, the OnFetchComplete will be called, so the P. And the P hides the "Wait" dialog and connects TDataSource.DataSet back to the dataset.
Also your "Wait" dialog may have a Cancel button, which an user may use to cancel a too long running query.
First of all - if you haven't much experience with multi-threading, don't start with the VCL classes. Use the OmniThreadLibrary, for (among others) those reasons:
Your level of abstraction is the task, not the thread, a much better way of dealing with concurrency.
You can easily switch between executing tasks in their own thread and scheduling them with a thread pool.
All the low-level details like thread shutdown, bidirectional communication and much more are taken care of for you. You can concentrate on the database stuff.
The db-thread creates all database components it needs when it is created
This may not be the best way. I have generally created components only when needed, but not destroyed immediately. You should definitely keep the connection open in a thread pool thread, and close it only once the thread has been inactive for some time and the pool disposes of it. But it is also often a good idea to keep a cache of transaction and statement objects.
If it receives a command, it performs the action and goes back to idle. During that time the main thread waits.
The first part is being handled fine when OTL is used. However - don't have the main thread wait, this will bring little advantage over performing the database access directly in the VCL thread in the first place. You need an asynchronous design to make best use of multiple threads. Consider a standard database browser form that has controls for filtering records. I handle this by (re-)starting a timer every time one of the controls changes. Once the user finishes editing the timer event fires (say after 500 ms), and a task is started that executes the statement that fetches data according to the filter criteria. The grid contents are cleared, and it is repopulated only when the task has finished. This may take some time though, so the VCL thread doesn't wait for the task to complete. Instead the user could even change the filter criteria again, in which case the current task is cancelled and a new one started. OTL gives you an event for task completion, so the asynchronous design is easy to achieve.
What's the best way to get the database results from the db-thread into the main thread?
I generally don't use data aware components for multi-threaded db apps, but use standard controls that are views for business objects. In the database tasks I create these objects, put them in lists, and the task completion event transfers the list to the VCL thread.
Main thread and db thread will never access the query at the same time.
With all components that load data on-demand you can't be sure of that. Often only the first records are fetched from the db, and fetching continues after they have been consumed. Such components obviously must not be shared by threads.
I have implemented both strategies: Thread pool and adhoc thread creation.
I suggest to begin with the adhoc thread creation, it is simpler to implement and simpler to scale.
Only move to a thread pool if (with careful evaluation) (1) there is a lot of resources (and time) invested in the creation of the thread and (2) you have a lot of creation requests.
In both cases you must deal with passing parameters and collect results. I suggest to extend the thread class with properties that allow this data passing.
Refer to the documentation of the classes, components and functions that the thread use to make sure they are thread safe, that is, they can be use simultaneously from different threads. If not, you will need to synchronize the access. In some cases you may find slight differences regarding thread safety. As an example, see DateTimeToStr.
If you create your thread at start and reuse it later whenever you need it, you have to make sure that you disconnect the db components (grid..) from the underlying datasource (disableControls) each time you're "processing" data.
For the sake of simplicity, I would inherit TThread and implement all the business logic in my own class. The result dataset would be a member of this class and I would connect it the db aware compos in with synchronize.
Anyway, it is also very important to delegate as much work as possible to the db server and keep the UI as lightweight as possible. Firebird is my favourite db server: triggers, for select, custom UDF dlls developed in Delphi, many thread safe db components with lots of examples and good support (forum) : jvUIB...
Good Luck

How to output data form a thread to another thread without locking?

I'm developing a DirectShow application. I encounter a deadlock problem, the problem seems caused by acquire lock in a callback function called from a thread. This is the quest I asked in MSDN forum:
http://social.msdn.microsoft.com/Forums/en-US/windowsdirectshowdevelopment/thread/f9430f17-6274-45fc-abd1-11ef14ef4c6a
Now I have to avoid to acquire lock in that thread. But the problem is, I have to output the audio to another thread, how can I put data to another thread without lock?
There's someone tell me that I can use PostMessage of win32 sdk to post data to another thread. But however, to get the message, I have to run a windows program. My program is a Python C++ extension module. That might be very difficult to add a loop to pull message. So I am think another way to pass data among threads without locking.
(Actually... the producer thread can't be locked, but the consumer thread can do that. )
To lock or not to lock, that's the question.
So the question is how to do?
Thanks.
------EDIT------
I think I know why I got a deadlock, that might not be the problem of DirectShow.
The main thread is own by Python, it call stop, namely, it hold GIL. And the stop wait for callback of DirectShow in thread return. But callback acquire the GIL.
It looks like this
Main(Hold GIL) -> Stop(Wait callback) -> Callback(Wait GIL) -> GIL(Hold by Main thread)
Damn it! That's why I don't like multi-thread so much.
No matter what, thanks your help.
If you were doing this in pure Python, I'd use a Queue object; these buffer up data which is written but block on read until something is available, and do any necessary locking under the hood.
This is an extremely common datatype, and some equivalent should always be available, whatever your current language or toolchain; there's a STL Queue available in C++, for instance, but the standard doesn't specify thread-safety characteristics (so see your local implementation docs).
Well, theoretically locks can be avoided if both of your threads can work on duplicate copies of the same data. After reading your question in the MSDN forum...
"So to avoid deadlock, I should not acquire any lock in the graber callback function? How can I do if I want to output audio to another thread?"
I think that you should be able to deposit your audio data in a dequeue (an STL class) and then fetch this data from another thread. This other thread can then process your audio data.
I am glad that your problem has been resolved the reason I asked about your Os was that the documentation you referred to said that you should not wait on other threads because of some problem with win16Mutexes. There are no win16mutexes on windows XP (except when programs are running on ntvdm/wow16) so you should be able to use locks to synchronize these threads.

Resources