Ruling out arbitrary cost copy construction?

Sean Kelly sean at invisibleduck.org
Thu Nov 4 15:35:51 PDT 2010


Steven Schveighoffer Wrote:
> 
> 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).

If a thread no longer exists then it doesn't matter who calls the finalizers so long as they aren't finalized concurrently by more than one thread.  To simplify things, the thread could notify the GC on termination so it could eagerly do whatever maintenance it wants to.

The only time this dtor wouldn't be called is for threads that terminate abnormally via pthread_exit or Windows TerminateThread, but because such threads have been left in an invalid state (uncalled dtors or other scoped code may have left mutexes locked, etc), finalizing any known data risks a deadlock or worse.  However, since these thread termination routines aren't supported in D (or C++ for that matter, as far as I know), not finalizing the data would simply be another effect of the resulting undefined behavior.

> You also need to provide a pointer in the object for a linked list for the  
> work-list.

The work-list could be a list of delegates.  Then the footprint of objects doesn't need to be altered.

> 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.

This is actually very easy, as druntime already differentiates between the two (the 'det' flag in rt_finalize).  I haven't thought enough about where the worklist code should live though.  All the GC knows about finalization is that it calls rt_finalize() on blocks with the FINALIZE bit set, but at the same time it's a perfect choke-point for iterating on the work-list when allocations are performed.

There are three situations that have th be dealt with:

1. The GC finalizes a shared object.
2. The GC finalizes an unshared object, but the GC was invoked by the object's owner thread.
3. The GC finalizes an unshared object, but the GC was invoked by another thread.

The GC would probably be the best place to track which thread owned what object so it would probably be the best place to store the work-list as well.  This is somewhat similar to how HOARD handles freed memory, so there is certainly a precedent for an allocator taking care of this sort of thing.

> 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.

Hm... this would delay the finalization of shared objects as well, but perhaps that doesn't matter since they can be safely finalized by any thread.  I'm still inclined to say that the GC should take care of the grunt work though, unless someone wants to argue that owner thread ID of every object should be stored in a new hidden field in the object itself.


More information about the Digitalmars-d mailing list