CodeRage 2022: Challenges of Multi-threaded Programming

Here you can find slides from my CodeRage 2022 presentation about Challenges of Multi-threaded Programming , as well as additional links to code examples related to the presentation. Slides: Additional links: Thread-safe Event Bus: Books: Delphi Event-based and Asynchronous Programming: Code Examples: Book: Delphi Thread Safety Patterns: Code Examples: Book: Delphi Memory Management: Code Examples: Book: Replay of the presentation can be found at:

Zeroing Weak Object References

In the two-part post series, The purpose of weak references - Part I and The purpose of weak references - Part II , I wrote about the purpose of weak references in automatic reference counting, as well as in manual memory management, where they are commonly referred to as non-owning references. In ARC, object references to reference-counted objects are unsafe, non-zeroing weak references, and in manual memory management, non-owning references to an object instance are also unsafe. Unsafe, in the above context, means that you can safely use such references only if the object instance they point to always has a longer lifetime than the unsafe reference, or that there is additional mechanism (code) that will notify you when the object is destroyed, so you know the reference is not pointing to a valid object anymore. In manual memory management, TComponent implements such a notification mechanism. However, there are two downsides: first, it only works with TComponent descendants; and

The purpose of weak references - Part II

In the first part of this post series, I covered owning and non-owning references under manual memory management, and the purpose of non-owning (weak) references in that memory model. Following the same use cases, we can now clearly show the purpose of their counterparts under the automatic reference counting memory model. Automatic reference counting Automatic reference counting is a memory model under which an object instance will be valid as long as there is at least one strong reference to that object instance. When the last strong reference goes out of scope or is nilled, the object's reference count will drop to zero, and the instance will be automatically destroyed. One of the side-effects of that design is that two object instances that are no longer reachable through any outside references can hold strong references to each other, thus keeping themselves alive and creating memory leaks. This is called a reference cycle. To prevent problems with reference cycles, ARC h

The purpose of weak references - Part I

The terminology "weak and strong references" is commonly used in the context of automatic reference counting. In the context of manual memory management, we talk about ownership, and owning and non-owning references. While the terminology is different, those two different kinds of references represent the same concept, regardless of the underlying memory management model. Strong references are the equivalent of owning references, and weak references are the equivalent of non-owning references. Understanding those relations can help us understand the purpose of weak references in automatic reference counting, and instead of thinking about them merely in the context of breaking reference cycles, we should think about them as non-owning references—in other words, additional references to an object instance that don't participate in its memory management, and could be invalidated after the object is released through other code and owning references. Because non-owning (wea

Delphi Thread Safety Patterns book available on Amazon

Delphi Thread Safety Patterns book is now available as paperback on Amazon, too. While the thread safety of a particular piece of code depends on the surrounding context and how it is used, some data types are inherently unsafe, and for some of them, thread safety will depend on the use case and the specific code. Unfortunately, when you look at some class, type declaration, or API in isolation, there is very little information there that will tell you whether instances of that type can be safely used in multiple threads, or under which conditions. The proper place to learn about the thread safety of an API is its documentation. However, most documentation will not explicitly give you that information. Occasionally, the documentation will mention that a particular feature is not thread-safe, or will tell you that a feature can be used in background threads, but for the most part, you will have to figure out thread safety on your own. One rea

FreeAndNil Debate: Thread Safety

One of the topics raised in yesterday's FreeAndNil debate was using FreeAndNil in multi-threaded code for avoiding access to a dangling reference when multiple threads are accessing and using the same object instance. Problem is that FreeAndNil is not thread-safe and cannot be used to achieve thread safety. You cannot call FreeAndNil on a shared object reference in one thread and then use if Assigned  in another to check whether object is still alive and then do something with that object. Your second thread can pass the if Assigned check and start working with the object while the first thread can destroy that object at any point. There is no mechanism in the FreeAndNil and if Assigned check that can prevent that. If you need to use shared object instance in such manner you need to use locking mechanism and lock all access, in all threads, to such an object. If you use locking mechanism, then you can use FreeAndNil in one thread and if Assigned check in another. I ment

Book Review: Delphi Legacy Projects

We are only few a years away from celebrating Delphi's thirtieth birthday. Because it has been here for quite some time, many Delphi projects are far from being brand-new, and almost every Delphi developer is or has previously worked on a project that can be considered a legacy project. Maintaining legacy projects is painful. Moving them to a newer Delphi version is even more so. A recently published book, written by Delphi expert William Meyer, "Delphi Legacy Projects", can help you ease some of that pain. It will guide the transformation of your legacy projects, help you bring them up to date, and make them more maintainable. Removing cruft, better organization, and less unit cycles can also significantly improve compile speed and IDE memory consumption. The book starts with an analysis of general problems in legacy projects and then presents strategies, one by one, that will help you tackle each individual problem. From project management issues, through dealing wit