"delphi: why vcl is not thread-safe? how can be?" Code Answer


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.

By Hafnernuss on May 28 2022

Answers related to “delphi: why vcl is not thread-safe? how can be?”

Only authorized users can answer the Search term. Please sign in first, or register a free account.