On Thu, 04 Nov 2010 14:38:59 -0400, Andrei Alexandrescu
<seewebsiteforem...@erdani.org> wrote:
Thanks to all for a very illuminating discussion. The dialog revealed
that the topic of cheap copy construction is oddly linked with the topic
of garbage collection: garbage collection calls destructors concurrently
with other code, which means reference count code must be interlocked,
which makes it not-so-cheap.
This is only a manifestation of a deeper problem: destructors can
execute arbitrary code, and, if ran in an arbitrary thread, can cause
all sorts of deadlocks and essentially render "shared" inoperant.
Walter and I discussed two possibilities this morning:
1. Never call class destructors (or never call them if more than one
thread is running)
2. Each destructor should be called in the thread that created the
object.
The second solution is quite attractive. It can be implemented by
associating each thread with a worklist - a list of objects to destroy.
The GC can run in any thread but it will not call destructors. Instead,
it adds objects to be destroyed to the threads that created them (this
means we need to add a field to each object with the thread ID of the
creating thread). When client code calls new, the allocation routine
will first inspect the worklist and call the destructors if needed.
I think this can be made to work and has good properties, although a
fair amount of details need to be figured out. Please share any thoughts
you may have.
What if a thread no longer exists? Would there be a way to mark such
dtors that need this feature? I don't know, because it seems to me like a
lot of band-aiding for something that is infrequently used (I've gotten
along fine in D without reference counting for as long as I've used it).
You also need to provide a pointer in the object for a linked list for the
work-list.
I'm thinking I would prefer to have the destructor and finalizer split, so
the 'destructor' can tell whether it's being called synchronously or from
the GC. Then the dtor itself can handle the whole worklist implementation.
I guess the only extra thing you would need in addition to that is a hook
so memory allocation from a given thread can be hooked to process the
worklist. Or maybe the worklist becomes a standard feature of the thread
class, and you manually add the task from the destructor instead of the GC
doing it for you.
-Steve