FreeAndNil Debate: Thread Safety
One of the topics raised in yesterday's FreeAndNil debate was using
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
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
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
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
FreeAndNil with assigning nil to an interface reference in
multi-threaded code, such code will not magically become thread-safe. You can
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
FreeAndNil on a shared object reference is not thread-safe
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
AtomicDecrement or equivalent