When do I need synchronize in TThread? - multithreading

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?

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.

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

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.

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.

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.

Multi-threaded access of components in Delphi

Can you suggest an approach when design-time components can be accessed both from general code (VCL or other) and from my own threads?
The problem is that when I have full control over my own threads I know exactly when I should access mutexes. In case of design-time elements I have no control at least of the code related to VCL.
One of the variants would be to wrap HandleMessage in a mutex access code. The idea behind this is that almost everything related to VCL comes from message processing code (the exception is direct SendMessage handling). But looking at the sources I see no "official" way to wrap message handling in any code fragment.
Don't even try to go there. Google for "global interpreter lock" (Python specific) to see what a bad idea such a bottleneck is.
If you need synchronized access to data, try to make the locked access as short as possible, and lock not any higher in the call chain than you absolutely must. If you have objects that are to be accessed from multiple threads, then synchronize inside their methods.

Resources