Delphi: Why VCL is not thread-safe? How can be? - multithreading

Everywhere is noticed that VCL is not thread-safe and we must synchronize access to it. So it's VCL faults that is not thread-safe.
How VCL itself can be thread-safe?

What, precisely, does "thread-safe" mean to you? What about someone else? Every time I see this brought up, it ends up boiling down to this: "I want VCL to be thread-safe so I don't have to think about threading and synchronization issues. I want to write my code as if it is still single-threaded."
No matter how much work went into making VCL so-called "thread-safe", there will always be situations where you can get into trouble. How would you go about making it thread-safe? I don't say this to be combative, rather I merely want to demonstrate that it is not a simple problem with a simple, "works-in-all-cases" solution. To highlight this, let's look at some potential "solutions."
The simplest and most direct approach I see is each component has some kind of "lock", say a mutex or critical section. Every method on the component grabs the lock on entry and then releases the lock just prior to exit. Let's continue down this path with a thought experiment. Consider how Windows processes messages:
Main thread obtains a message from the message queue and then dispatches it to the appropriate WndProc. This message is then routed to the appropriate TWinControl component. Since the component has a "lock", as the message is routed to the appropriate message handler on the component, the lock is acquired. So far so good.
Now take the proverbial button-click message processing. The OnClick message handler is now called which will most likely be a method on the owning TForm. Since the TForm descendant is also a TWinControl component, the TForm's lock is now acquired while the OnClick handler is processed. Now the button component is locked and the TForm component is also locked.
Continuing on this line of thinking, suppose the OnClick handler now wants add an item to a listbox, listview, or some other visual list or grid component. Now suppose some other thread (not the main UI thread) is already in the midst of accessing this same component. Once a method is called on the list from the UI thread it will attempt to acquire the lock, which it cannot since the other thread is currently holding it. As long as the non-UI thread doesn't hold that lock for very long, the UI thread will only block for a brief period.
So far so good, right? Now suppose, that while the non-UI thread is holding the list control's lock, a notification event is called. Since, it will most likely be a method on the owning TForm, upon entry to the event handler, the code will attempt to acquire the lock for the TForm.
Do you see the problem? Remember the button OnClick handler? It already has the TForm lock in the UI thread! It is now blocked waiting for the lock on the list control, which the non-UI thread owns. This is a classic dead-lock. Thread A holds lock A and attempts to acquire lock B which is held by thread B. Thread B is at the same time attempting to acquire lock A.
Clearly, if every control/component has a lock that is automatically acquired and released for every method isn't a solution. What if we left the locking up to the user? Do you see how that also doesn't solve the problem either? How can you be certain that all the code you have (including any third-party components) properly locks/unlocks the controls/components? How does this keep the above scenario from happening?
What about a single shared lock for the whole of VCL? In this scenario, for each message that is processed, the lock is acquired while the message is processed regardless of what component the message is routed to. Again, how does this solve a similar scenario I described above? What if the user's code added other locks for synchronization with other non-UI threads? Even the simple act of blocking until a non-UI thread terminates can cause a dead lock if it is done while the UI thread holds the VCL lock.
What about non-UI components? Database, serial, network, containers, etc...? How should they be handled?
As excellently explained by the other answers, Windows already does a pretty decent job of properly segregating UI message processing to only the thread on which each HWND is created. In fact, learning precisely how Windows works in this regard will go a long way to understanding how you can write your code to work with Windows and VCL in a manner that avoids most of the pitfalls I highlighted above. The bottom line is writing multi-threaded code is difficult, requires a rather drastic mental shift, and lots of practice. Read as much as you can on multi-threading from as many sources as possible. Learn and understand as many coding examples of "thread-safe" code as you can, in any language.
Hopefully this was informative.

The VCL is not thread safe. It is a wrapper around Win32. Win32 is thread safe but has threading rules that give meaning to that statement. Most specifically a window has affinity to the thread that created it.
The design of the Windows message queue means that it is almost always preferable to have all your GUI windows created by the main thread. The VCL designers decided that it was reasonable only to support that mode of operation. And so all VCL code must be executed from the main thread.
There's nothing that can be done to change this. This is by design. If you wish to execute VCL code, it must be done on the main thread. Use TThread.Synchronize or TThread.Queue to arrange that.

There are a lot of reasons why the VCL (especially UI controls) is not thread safe.
Race conditions on message input, especially in code that directly calls TControl.Perform()/TObject.Dispatch() instead of using PostMessage()/SendMessage(). The former does not perform any synchronizing of the control's message handlers, but the latter does. So it is not safe to perform non-HWND based messages from outside of the main thread.
An HWND has thread affinity. It receives and processes messages only on, and can be destroyed only on, the thread context that creates it. A TWinControl can destroy and recreate its HWND at any time, even multiple times, during its lifetime. The TWinControl.Handle property getter creates a new HWND if none exists yet. So if the control is in the process of recreating its HWND when another thread reads from the Handle property, the control can end up with a new HWND that was created in the wrong thread context, making the control no longer responsive to the main message loop (and can potentially leak a second HWND as well). So it is not safe to read from the TWinControl.Handle property from outside of the main thread.
The VCL has a MakeObjectInstance() function that creates a dynamic proxy to allow a TWndMethod class method to be used as a Win32 WNDPROC window callback procedure. All TWinControl controls, and some utility classes like TTimer, use this function. Internally, it maintains a global linked list of proxies, and that list is not protected from concurrent access across threads. So it is not safe to create/destroy HWND-based VCL controls from outside of the main thread.
I'm sure there are other reasons, but these are the big ones.

Related

Form.ShowModal not working on TThread [duplicate]

Everywhere is noticed that VCL is not thread-safe and we must synchronize access to it. So it's VCL faults that is not thread-safe.
How VCL itself can be thread-safe?
What, precisely, does "thread-safe" mean to you? What about someone else? Every time I see this brought up, it ends up boiling down to this: "I want VCL to be thread-safe so I don't have to think about threading and synchronization issues. I want to write my code as if it is still single-threaded."
No matter how much work went into making VCL so-called "thread-safe", there will always be situations where you can get into trouble. How would you go about making it thread-safe? I don't say this to be combative, rather I merely want to demonstrate that it is not a simple problem with a simple, "works-in-all-cases" solution. To highlight this, let's look at some potential "solutions."
The simplest and most direct approach I see is each component has some kind of "lock", say a mutex or critical section. Every method on the component grabs the lock on entry and then releases the lock just prior to exit. Let's continue down this path with a thought experiment. Consider how Windows processes messages:
Main thread obtains a message from the message queue and then dispatches it to the appropriate WndProc. This message is then routed to the appropriate TWinControl component. Since the component has a "lock", as the message is routed to the appropriate message handler on the component, the lock is acquired. So far so good.
Now take the proverbial button-click message processing. The OnClick message handler is now called which will most likely be a method on the owning TForm. Since the TForm descendant is also a TWinControl component, the TForm's lock is now acquired while the OnClick handler is processed. Now the button component is locked and the TForm component is also locked.
Continuing on this line of thinking, suppose the OnClick handler now wants add an item to a listbox, listview, or some other visual list or grid component. Now suppose some other thread (not the main UI thread) is already in the midst of accessing this same component. Once a method is called on the list from the UI thread it will attempt to acquire the lock, which it cannot since the other thread is currently holding it. As long as the non-UI thread doesn't hold that lock for very long, the UI thread will only block for a brief period.
So far so good, right? Now suppose, that while the non-UI thread is holding the list control's lock, a notification event is called. Since, it will most likely be a method on the owning TForm, upon entry to the event handler, the code will attempt to acquire the lock for the TForm.
Do you see the problem? Remember the button OnClick handler? It already has the TForm lock in the UI thread! It is now blocked waiting for the lock on the list control, which the non-UI thread owns. This is a classic dead-lock. Thread A holds lock A and attempts to acquire lock B which is held by thread B. Thread B is at the same time attempting to acquire lock A.
Clearly, if every control/component has a lock that is automatically acquired and released for every method isn't a solution. What if we left the locking up to the user? Do you see how that also doesn't solve the problem either? How can you be certain that all the code you have (including any third-party components) properly locks/unlocks the controls/components? How does this keep the above scenario from happening?
What about a single shared lock for the whole of VCL? In this scenario, for each message that is processed, the lock is acquired while the message is processed regardless of what component the message is routed to. Again, how does this solve a similar scenario I described above? What if the user's code added other locks for synchronization with other non-UI threads? Even the simple act of blocking until a non-UI thread terminates can cause a dead lock if it is done while the UI thread holds the VCL lock.
What about non-UI components? Database, serial, network, containers, etc...? How should they be handled?
As excellently explained by the other answers, Windows already does a pretty decent job of properly segregating UI message processing to only the thread on which each HWND is created. In fact, learning precisely how Windows works in this regard will go a long way to understanding how you can write your code to work with Windows and VCL in a manner that avoids most of the pitfalls I highlighted above. The bottom line is writing multi-threaded code is difficult, requires a rather drastic mental shift, and lots of practice. Read as much as you can on multi-threading from as many sources as possible. Learn and understand as many coding examples of "thread-safe" code as you can, in any language.
Hopefully this was informative.
The VCL is not thread safe. It is a wrapper around Win32. Win32 is thread safe but has threading rules that give meaning to that statement. Most specifically a window has affinity to the thread that created it.
The design of the Windows message queue means that it is almost always preferable to have all your GUI windows created by the main thread. The VCL designers decided that it was reasonable only to support that mode of operation. And so all VCL code must be executed from the main thread.
There's nothing that can be done to change this. This is by design. If you wish to execute VCL code, it must be done on the main thread. Use TThread.Synchronize or TThread.Queue to arrange that.
There are a lot of reasons why the VCL (especially UI controls) is not thread safe.
Race conditions on message input, especially in code that directly calls TControl.Perform()/TObject.Dispatch() instead of using PostMessage()/SendMessage(). The former does not perform any synchronizing of the control's message handlers, but the latter does. So it is not safe to perform non-HWND based messages from outside of the main thread.
An HWND has thread affinity. It receives and processes messages only on, and can be destroyed only on, the thread context that creates it. A TWinControl can destroy and recreate its HWND at any time, even multiple times, during its lifetime. The TWinControl.Handle property getter creates a new HWND if none exists yet. So if the control is in the process of recreating its HWND when another thread reads from the Handle property, the control can end up with a new HWND that was created in the wrong thread context, making the control no longer responsive to the main message loop (and can potentially leak a second HWND as well). So it is not safe to read from the TWinControl.Handle property from outside of the main thread.
The VCL has a MakeObjectInstance() function that creates a dynamic proxy to allow a TWndMethod class method to be used as a Win32 WNDPROC window callback procedure. All TWinControl controls, and some utility classes like TTimer, use this function. Internally, it maintains a global linked list of proxies, and that list is not protected from concurrent access across threads. So it is not safe to create/destroy HWND-based VCL controls from outside of the main thread.
I'm sure there are other reasons, but these are the big ones.

In which thread methods should Synchronize be used?

I know Synchronize must be used in the Execute procedure, but should it be used in Create and Destroy methods too, or is it safe to do whatever I want?
I know Synchronize must be used in the Execute procedure.
That is somewhat vague. You need to use Synchronize when you have code that must execute on the main thread. So the answer to whether or not you will need to use Synchronize depends crucially on what the code under consideration actually does. The question that you must ask yourself, and which is one that only you can answer, is do you have code that must run on the main thread?
As a general rule it would be considered prudent for you not to need to call Synchronize outside the Execute method. If you can find a way to avoid doing so then that would be wise. Remember that the ideal scenario with threads is that they never need to block with Synchronize if at all possible.
You might also wish to consider which thread executes the constructor and destructor.
The constructor Create runs in the thread that calls it. It does not run in the newly created thread. Therefore it is unlikely that you would need to use Synchronize there.
The destructor Destroy runs in the thread that calls it. Typically this is the thread that calls Free on the thread object. And usually that would be called from the same thread that originally created the thread. The common exception to that is a FreeOnTerminate thread which calls Free from the thread.
There is a need to use Synchronize() when the code is executing outside of the context of the main (GUI) thread of the application. Therefore the answer to your question depends on whether the constructor and destructor are called from that thread or not.
If you are unsure you can check that by comparing the result of the Windows API function GetCurrentThreadId() with the variable MainThreadID - if they equal the code executes in the context of the main thread.
Threads that have FreeOnTerminate set will have their destructor called from another thread context, so you would need to use Synchronize() or Queue(). Or you use the termination event the VCL already provides, I believe it is executed in the main thread, but check the documentation for details.
First of all, you don't want to call Synchronize() unnecessarily, because that simply defeats the purpose of using a thread. So the decision should be based on whether: (a) it's possible to encounter race conditions with shared data. (b) you'll be using VCL code which usually has to run on the main thread.
It's unlikely you would need to synchronise in the constructor because TThread instances are usually created from the main thread already. (The exception being if you're creating some TThread's from another child thread.)
NOTE: It won't cause any harm though because Synchronize() already checks if you're on the main thread and will call the synchronised method immediately if you are.
class procedure TThread.Synchronize(ASyncRec: PSynchronizeRecord; QueueEvent: Boolean = False);
var
SyncProc: TSyncProc;
SyncProcPtr: PSyncProc;
begin
if GetCurrentThreadID = MainThreadID then
ASyncRec.FMethod
As for the destructor there are 3 usage patterns:
The TThread instances destroys itself.
Another thread (possibly the main thread) can WaitFor the instance to finish, then destroy it.
You can intercept the OnTerminate event. This is fired when the instance is finished, and you could then destroy it.
NOTE: The OnTerminate event will already be synchronised.
procedure TThread.DoTerminate;
begin
if Assigned(FOnTerminate) then Synchronize(CallOnTerminate);
end;
Given the above, the only time you might need to synchronise is if the thread self-destructs.
However, I'd advise that you rather avoid putting code into your destructor that might need to be synchronised. If you need some results of a calculation from your thread instance, OnTerminate is the more appropriate place to get this.
To add to what has been said in other answers...
You never need to use Synchronize at all. Synchronize may be useful, however, in the following circumstance:
In the context of your thread you need to execute code that touches objects that have affinity to the main thread.
You require your thread to block until that code has been executed.
Even in that case, there are other ways to achive the same goal, but Synchronize provides a convenient way to satisfy those two needs. If you need only one of those two items, there are better strategies available.
On topic #1, the obvious objects are user interface objects. These are objects that have thread affinity to the main thread simply by virtue of the fact that the main thread is continually reading and writing the properties of those objects (not the least because it needs to paint them to the screen, etc) and it does so at its own convenience. This means that your thread cannot safely access those components with a guarantee that the main thread will not also be accessing or modifying them at the same time. In order to prevent corruption, the thread has to pass the work to the main thread (since the main thread can only do one thing at a time and can't, obviously, interfere with itself). Synchronize simply places the work onto the main thread's queue and waits until the main thread gets around to completing it before returning.
This gets to point #2. Do you need to (or, equally, can you afford to) wait around until the main thread finishes the work? There are three cases and two options.
Yes, you can or must wait. (Synchronize is a good fit)
No, you cannot wait. (Synchronize is not a good fit)
Don't care. (Synchronize is easy, so it's a sensible option)
If you are simply updating a status display that will soon be overwritten anyway and your thread has more pressing issues, then it's probably sensible to just post a message to the main thread and carry on doing things, for example. If your thread is just waiting around doing nothing, mostly, and it's not worth the time to code anything more sophisticated, then Synchronize is just fine, and it can be replaced with something better if needs dictate so in the future.
As others have said, it really depends on what you are doing. The more important question, I think, at least conceptually, is to sort out when you need to worry about concurrency and when you don't. Any time you have more than one thread that requires access to a single resource you need to use some sort of mechanism to coordinate that access to avoid the threads crashing into each other. Synchronize is one of those methods, but it not the least nor the last of them.

Do we have to use Synchronize if we want to make some changes in the VCL main thread?

Let's say that I want to simply change the caption of a Label when the program is in a child thread. I don't want use Synchronize. I really don't want to get the OS switch to another thread context to do this job. I know that I can't do this by just putting some lock(Semaphore or something) in my child thread. Can anyone tell me the reason why I can't use locks for that?
Thanks in advance :)
Do we have to use Synchronize if we want to make some changes in the VCL main thread?
Yes.
Well, code that accesses VCL objects has to execute on the main thread and Synchronize is the most commonly used way to achieve that. There is no way around that constraint.
David's answer is 100% correct. But I thought I'd shed a little more light...
Imagine this scenario: You have a VCL component with a number of properties which you want to update from a thread. You create a lock (such as a critical section) and any call in both your main VCL thread and additional thread you respect this lock whenever trying to access that object and its properties. However, since the VCL doesn't acknowledge the presence of other threads trying to use it, there may be something in the main thread which tries to access the same property that your thread is trying to access... at the same time. I'm not talking about your own code which might access this property, but something behind the VCL its self. There's no way that the VCL its self knows about your lock to acknowledge it.
Therefore, even the best locking mechanisms are not safe when working with anything in the main thread. Synchronize is an essential part of how multi-threading works, although there are a few alternatives such as feeding windows messages.
Scenario
Let's say you create a custom button component inherited from TButton. You create a thread behind this button and want to update the caption of the button from within this thread. You create a critical section lock to protect your control.
Let's also say that you have an action manager and this button is assigned to an action. The action manager is responsible for updating the caption of the button. While your thread and all your code respects the lock when accessing your button control, the action manager has no concept of this and tries to go ahead and update the caption anyway.

When do I need synchronize in TThread?

I know that you need synchronize (yourprocedure) to set e.g. a label's text.
But what about:
Reading a label's text.
Toggle/Set the label's enabled property.
Call other labels procedures/functions (e.g. onclick event).
Is there an easy rule to know/remember when I need to use synchronize?
PS.: Is synchronize similar to PostMessage/SendMessage?
Easy rule of thumb: ANY access to VCL UI components needs to be synchronized. That includes both reading and writing of UI control properties. Win32 UIs, most notably dialogs like MessageBox() and TaskDialog(), can be used directly in worker threads without synchronizing.
TThread.Synchronize() is similar to SendMessage() (in fact, it used to be implemented using SendMessage() internally in Delphi 5 and earlier). TThread.Queue() is similar to PostMessage().
Any time you access a VCL UI component, you need to implement some type of thread safety measure. This is also, typically, the case when you're accessing a variable or procedure that exists or will be accessed by another thread. However, you don't need to use the Synchronize method in all of these situations. There are other tools at your disposal, and Synchronize is not always your best solution.
Synchronize blocks both the main thread and the calling thread while it's performing the procedure that you pass to it, so overusing it can detract from the benefits of multi-threading. Synchronize is probably most commonly used for updating your UI, but if you find that you're having to use it really frequently, then it might not be a bad idea to check and see if you can restructure your code. I.E. do you really need to read labels from within your thread? Can you read the label before starting the thread and pass it into the thread's constructor? Can you handle any of these tasks in the thread's OnTerminate event handler?

Updating VCL from the same thread that created the UI. Why?

I know that I must call Synchronize to update the vcl from a thread that did not create the controls or send a message to the window.
I have often heard the word not thread safe but I can't find an actual explanation about what is happening.
I know the application might crash with an access violation, but again I don't know why?
Please shed a light on this topic.
One of the biggest causes of the thread-unsafety in the VCL UI controls is the TWinControl.Handle property getter. It is not just a simple read-only accessor of the control's HWND. It also creates the HWND if it does not exist yet. If a worker thread reads the Handle property when no HWND exists yet, it creates a new HWND within the worker thread context, which is bad because HWNDs are tied to the creating thread context, which would render the owning control pretty much inoperable at best since Windows messages for the control would not go through the main message loop anymore. But worse, if the main thread reads the same Handle property at the same time the worker thread does (for instance, if the main thread is dynamically recreating the Handle for any number of reasons), there is a race condition between which thread context creates the HWND that gets assigned as the new Handle, as well as a potential handle leak potential if both threads end up creating new HWNDs but only one can be kept and the other gets leaked.
Another offender to thread-unsafety is the VCL's MakeObjectInstance() function, which the VCL uses internally for assigning the TWinControl.WndProc() non-static class method as the message procedure of the TWinControl.Handle window, as well as assigning anyTWndMethod-typed object method as the message procedure of the HWND created by the AllocateHWnd() function (used by TTimer for example). MakeObjectInstance() does quite a bit of memory allocating/caching and twiddling of that memory content which are not protected from concurrent access by multiple threads.
If you can ensure a control's Handle is allocated ahead of time, and if you can ensure the main thread never recreates that Handle while the worker thread is running, then it is possible to safely send messages to that control from the worker thread without using Synchronize(). But it is not advisable, there are just too many factors that the worker thread would have to take into account. That is why it is best that all UI access be done in the main thread only. That is how the VCL UI system is meant to be used.
About GDI thread safety in Windows, see this reference article.
It clearly states that you can access safely handles from multiple threads, but that it should not be made at the same time. You need to protect access to GDI handles, e.g. using critical sections.
Remember that GDI handles, like most Windows handles, are pointers of internal structures mapped to an integer (NativeUInt under newer Windows, for 64 bit compatibility). Like always in multi-thread computing, accessing the same content concurrently can be source of problems, which are very difficult to identify and fix.
The UI part of the VCL itself was never meant to be thread-safe, from the beginning, since it was relying on the non-thread-safe Windows API. For instance, if you release a GDI object in a thread, which is still needed in another thread, you'll face potential GPF.
Embarcadero (at this time) could have made the VCL thread-safe, serializing all UI access via critical sections, but it may have added complexity, and decreased overall performance. Note that even Microsoft .Net platform (in both WinForms and WPF) also requires a dedicated thread for UI access, AFAIK.
So, to refresh UI from multiple threads, you have several patterns:
Use Synchronize calls from the thread;
Send a GDI custom message (see WM_USER) from the background threads to notify the UI thread that a refresh is needed;
Have a stateless approach: the UI will refresh its content from time to time, from the logic layer (using a timer or when you press some buttons which may change the data).
From my point of view, I prefer option 2 for most UIs, and an additional option 3 (which can be mixed with option 2) for remote client-server access. Therefore, you do not have to want from the server side to trigger some update event to the UI. In a HTTP/AJAX RESTful world, this does definitively make sense. Option 1 is somewhat slow, IMHO. In all cases, options 2 and 3 expect a clear n-Tier layered architecture, in which logic and UI are not mixed: but this is a good pattern to follow anyway, for any serious development.
Windows controls with handles are not thread-safe (i.e. they cannot be accessed safely by two different threads at the same time), and Delphi wraps the Windows controls to give you the VCL controls. Since the controls ARE accessed by the main GUI thread, you need to leave them alone if you are executing another thread.

Resources