Ruling out arbitrary cost copy construction?

Steven Schveighoffer schveiguy at yahoo.com
Thu Nov 4 15:57:29 PDT 2010


On Thu, 04 Nov 2010 18:35:51 -0400, Sean Kelly <sean at invisibleduck.org>  
wrote:

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

Right, but in Andrei's idea (from what I can tell), the GC does not call  
destructors, it just adds to thread-specific worklists.

But I think it's a non-issue.  Just stick it on the worklist of the  
current thread, since the dead thread doesn't care anymore.  I'm assuming  
the current thread's worklist is cleaned at the end of the GC cycle.

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

Yes, but then you need to allocate memory to hold the delegates.  I don't  
know if this is a efficient use of memory.  Why not just bump up the size  
of an object by one pointer?

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

4. A thread exits with a non-empty worklist.  I think this might reduce to  
case 2, but it's not a case where you're already taking the global GC lock  
(vs. cleaning up when you call new).

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

It could be in the Thread object, or in a thread's TLS.  I feel the Thread  
object is much easier to get at from another thread than another thread's  
TLS, or is there an easy way to do this?

Hm... I just had a thought -- what is going to be the performance of  
continuously looking up the right worklist to add to based on the thread  
ID?

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

There might be no point to use this weird scheme for shared objects -- you  
need to use locking to do reference counting anyways, so you might as well  
just do that.

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

I think that is what Andrei is suggesting.  Unless we want to change the  
language to be able to flag reference counted types so the GC can see that.

Can we encapsulate all this function into a member?  So for instance you  
just add a RefCount type in your struct, and it contains the code to deal  
with this problem?

-Steve


More information about the Digitalmars-d mailing list