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 mentioned that in such scenarios, instead of manually managed object instances and locks, you can use reference counted class with automatic memory management and interface references to achieve thread safety, as clearing the interface reference will be thread-safe operation.

But, what I said was only the half of the story and literally applied it is not correct. Stefan Glienke pointed that out after the debate and I have to tell the full story, otherwise it will seem like interface references have some magical thread safety feature which they don't. I apologize for any confusion.

In other words, shared interface references are just as unsafe as regular object references. If you just replace object reference with interface reference, and calling FreeAndNil with assigning nil to an interface reference in multi-threaded code, such code will not magically become thread-safe. You can still pass if Assigned check on interface reference and work on the reference in one thread, while another thread will nil that reference while you are still using it. Assigning nil to a shared interface reference is not thread-safe, just like calling FreeAndNil on a shared object reference is not thread-safe either.

What interface references and automatic memory managed instances allow you to do is to have multiple, unshared, references to a shared object instance. And as long as some of those references is alive, that object instance will be alive and valid, too. With manually managed object instances, you cannot have multiple references to an object as they will become dangling pointers if one thread can destroy the object while others are still using it.

What is thread-safe in an interface references scenario, is each thread having its own strong reference (acquired before thread started running) to an object instance and assigning nil to such unshared reference in a thread and potentially releasing the object is a thread-safe operation.

Note: There is additional requirement for such reference counted, automatically managed classes, and that is that reference counting is performed atomically—using AtomicIncrement and AtomicDecrement or equivalent functions.

Comments

Popular posts from this blog

Coming in Delphi 12: Disabled Floating-Point Exceptions

Assigning result to a function from asynchronous code

Beware of loops and tasks