It’s fair to say that it is possible to be a good software developer, whether you’re writing cross platform apps, or preferring to stick to Windows development, and never really ‘get your hands dirty’ with such things like the ASM
keyword. In fact, you can live a perfectly care-free programmer life without even knowing what the lower-level things like the ASM
keyword do. I’m all for that. It’s one of the strengths of Delphi, low code, sometimes even no code, component-based development means you keep all the really mind-bending crazy professor things at arm’s length. But sooner or later, if you create enough apps, you will find that there is a moment when your beautifully themed user interface suddenly goes a deathly shade of pale and Windows helpfully tells you that your application has stopped responding. It’s usually when you’re doing something in the background and that something is taking all the application’s CPU time so that there’s no time left for it to do things like update the user interface and respond to the regular “are you dead?” messages from the operating system. You’ve hit the limits of doing everything in the main thread.
Table of Contents
The solution to a responsive user interface is the use of threads
The good news is there’s a solution to this: threads. In fact, multiple threads because, technically, you’re already using one thread perhaps without really knowing it; the main thread, which is where the Delphi runtime library does all the important things like updating the user interface, responding to events, clicks and presses. But to be clear, we’re talking about additional threads which you add into your code so that things like long calculations execute either in parallel to the main thread or co-operatively time sharing and safely synchronizing when the time comes for all the efforts of the threads to join together their results and perhaps update some graphics or on-screen text. With only the main thread around there is sometimes not enough CPU cycles available to do all the things you want like running SQL queries, calculating checksums and respond to requests to repaint areas of the screen and when your app doesn’t reply to the operating systems “are you dead” watchdog mechanism the OS assumes your code has crashed or entered a never-ending loop and as a result it has ‘stopped responding’.
Is there a way to get the user interface to respond without using threads?
Some of you may be aware of the application.processmessages
method. If you pepper this around some slow code it can help give some time back to the runtime library’s main thread so it can explicitly process those “are you dead” keep alive messages from the operating system.
It looks like this:
1 2 3 4 5 6 7 8 9 10 |
procedure TForm.DoSomethingSlow; var i: LongInt; begin for i := 1 to 1000000 do begin if i mod 100 = 0 then Application.ProcessMessages; Label1.Caption := 'Counter: ' + IntToStr(i); end; end; |
[I have deliberately written this in an older style of Delphi code because that’s where you’re probably going to find it!]
Without the Application.ProcessMessages
line the caption would likely not get updated until the loop has finished running. If you were to grab the title bar of the application with your mouse, you’ll probably find Windows will tell you the application is not responding. Add in the processmessages
call and the app’s message queue will be given time to process things, hence the name, and the keep alive mechanism from Windows will hopefully get processed in time and in turn it might make the loop less prone to making your application appear unresponsive. Note that I say ‘might’, because really the only way to better guarantee long processes do not lock up the main user interface is to use multi-tasking and the thread mechanisms available to us in Delphi.
But before you rush off to pepper your code with Process Messages
calls you should know that it really doesn’t solve anything much and, in fact, is likely to end up causing all sorts of problems of its own. It’s not a cheap way to do multi-tasking. In fact, if possible, you should never use it.
The difference between a software developer and a senior developer is the use of threads
Well, maybe I should say it’s one of the signs of a senior developer – there are plenty of other ingredients that going into the recipe for greatness. Honestly though, if you take a look at any apps written by experienced senior software developers you will start to see keywords like TThread
and TTask
cropping up. I’m going to level with you. Threads are not always easy. It can take a bit of a change in mindset to first of all understand how to use threads and then it can take the patience of several saints to debug threads, especially the dreaded deadlock. But learning how to use the various thread libraries and constructs in Delphi, of which we are blessed with a rich selection, you’ll start to see some significant advantages, and so will your users as they find your apps speed up and respond to their keypresses and mouse clicks in a timely fashion. Using threads adds that extra polish and professional Je ne sais quoi secret sauce to your apps.
If they are so good, why don’t more people use threads in their apps?
Well, to be honest, when threads don’t work the way they’re supposed to they can be fiendishly difficult to debug. Threads can’t simply access memory locations and other objects without a lot of thought going into it and care taken to prevent accesses to data another thread is also trying to simultaneously update. This is particularly true for the elements of your user interface. Your threads can’t simply change the caption on a label control, for example, without the potential for inadvertently interfering with the main thread.
What does “thread safe” mean?
When code doesn’t access these shared objects and memory items correctly, they are referred to as not being “thread safe”.
To co-operate with other threads and the main thread (which handles all the UI updating), the thread needs to use synchronization methods. Luckily Delphi has a whole bunch of ways of doing this. Not so luckily this is only half the battle. Properly updating objects which are, or could be, shared among threads, is a bit of an art in itself but code which does do it properly is referred to as “thread safe”
Making code thread safe sounds complicated
Well, it can be and it’s not always obvious when something is not thread safe. I have some good news for you though. A thoroughly excellent new book has just been published which has a whole in-depth discussion on the vagaries of how threads work, what can go wrong, and, thankfully for us mere mortals, a set of ready-made design patterns which can be used in your own code to add threads which are “thread safe”.
Delphi Thread Safety Patterns by Dalija Prasnikar and Neven Prasnikar Jr.
I’ve written about Dalija’s other books before and interviewed her for this blog. Dalija is a quite incredibly smart person. I am fortunate that my involvement with Delphi means I get to know some very clever developers. Back in the days when I used to be a professional Poet (there are pictures and everything) we used to say that you could tell a lot about the mind of a poet by reading the poems they wrote. Well, I can tell you this translates very well into the Delphi Thread Safety Patterns book because it is a remarkable triumph of a reference and guide to everything you could ever need to know about threads and thread safety. Dalija must have a quite burgeoning intellect directing her thoughts.
It is a staggeringly good book. I know I am prone to an abundance of superlatives thanks to my formal British education and upbringing but really, this is a book everyone who is serious about development with Delphi should have, in fact I’d go so far as to say it’s essential no matter how much experience you’ve had in software development.
Why do you need the Delphi Thread Safety Patterns book?
The book is a dense examination of every possible angle there could be regarding the use of threads, the principles of what makes certain types of code thread safe or unsafe. It discusses, in depth the areas of the VCL functionality which are completely safe to use in threads – spoiler alert, Dalija asserts the VCL is not thread safe. She even covers some quite esoteric subjects like the use of the Floating Point Control Register (FPCR) and how that differs from one platform to another. That’s some pretty intense thinking. If there is something which is or is not thread safe this book must surely have covered it.
How is the book laid out?
The text is structured into six sections. Part one is a general primer on what it means for some code to be thread safe and why a worrying tsunami of code is either definitely or probably unsafe. After reading through the first part, I started to doubt that I’ve ever written a piece of code which wasn’t about to smash a hundred threads into a million pieces.
The later sections explore broader topics such as the VCL functions, standard controls, things like the right and wrong way to retrieve FormatSettings
and core language functions or features. Every part is laid out with color-coded callouts – red for code examples which are not thread safe, green for those that either are inherently thread safe or contain a suggested code pattern which mitigates the unsafe behavior.
Does the book actually contain thread-safety design patterns?
Yes, absolutely. The book is bursting at the seams with a myriad of ready-to-use code which implements useful constructs like thread-safe singleton classes, timers, graphic classes and component use, logging frameworks, REST client usage and even regular expressions. I defy anyone – except Dalija – to name off the top of their head which RegEx functions are or are not thread safe.
Where possible Dalija gives ways to do things in a thread safe manner with a clear, lucid explanation of why something is or is not safe and how it can be made to be safe or why that can never be done.
The book’s penultimate chapter contains an event bus mechanism with a publish and subscribe architecture complete with full source code. That chapter in itself is a gem which justifies getting the book but just to round things off the final chapter is a whole examination of performance measurement and profiling. The book closes off with an appendix listing a comprehensive set of references which themselves could be described as the definitive required reading list for Delphi programmers.
All the example source code in the book is available on Dalija’s GitHub repository.
I mean it when I say this: buy this book.
Book: Delphi Thread Safety Patterns
Author: Dalija Prasnikar and Nevin Prasnikar Jr.
Available from the author’s website: https://dalija.prasnikar.info/delphitspatt/
Design. Code. Compile. Deploy.
Start Free Trial Upgrade Today
Free Delphi Community Edition Free C++Builder Community Edition