Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
April 30, 2015 Destruction in D | ||||
---|---|---|---|---|
| ||||
After reading GC page in the reference, it seems that class destructors are called on a separate thread, in parallel to the main thread. Is this correct? What about structs? Are the destructors called when they go out of scope in a C++ RAII fashion, or do they happen on a separate thread too? I'm asking because one of the advantages listed for using a GC was something about not having to set up a special stack frame for destructors. I don't fully understand that point, but it seems like it would be incorrect if D structs destructed at end of scope. |
April 30, 2015 Re: Destruction in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise | On Thursday, 30 April 2015 at 20:07:11 UTC, bitwise wrote: > After reading GC page in the reference, it seems that class destructors are called on a separate thread, in parallel to the main thread. Is this correct? There's no guarantee what thread will be used in the standard GC implementation AFAIK. > > What about structs? Are the destructors called when they go out of scope in a C++ RAII fashion, or do they happen on a separate thread too? If they're on the stack(not allocated with `new`), then they have their destructor called upon leaving scope ala C++ RAII, otherwise see above. |
April 30, 2015 Re: Destruction in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise | On Thursday, 30 April 2015 at 20:07:11 UTC, bitwise wrote: > destructors are called on a separate thread, in parallel to the main thread. Is this correct? Not necessarily. the way the GC works in D today is whenever any thread allocates, it runs the GC functions which might do a collection. This is where the destructors run, too. So a destructor may be run by whatever random thread happened to run out of memory and triggered the collection cycle. > What about structs? Are the destructors called when they go out of scope in a C++ RAII fashion, or do they happen on a separate thread too? structs work basically the same as C++, yes. I don't know about your third thing... |
April 30, 2015 Re: Destruction in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Adam D. Ruppe | On Thu, 30 Apr 2015 16:17:10 -0400, Adam D. Ruppe <destructionator@gmail.com> wrote:
> On Thursday, 30 April 2015 at 20:07:11 UTC, bitwise wrote:
>> destructors are called on a separate thread, in parallel to the main thread. Is this correct?
>
> Not necessarily. the way the GC works in D today is whenever any thread allocates, it runs the GC functions which might do a collection. This is where the destructors run, too.
>
> So a destructor may be run by whatever random thread happened to run out of memory and triggered the collection cycle.
>
>> What about structs? Are the destructors called when they go out of scope in a C++ RAII fashion, or do they happen on a separate thread too?
>
> structs work basically the same as C++, yes.
>
>
> I don't know about your third thing...
Well, the third thing was just my reasoning for asking in the first place. I need to be able to acquire/release shared resources reliably, like an OpenGL texture, for example.
Come to think of of though, I haven't thought this issue through with regard to multi-threaded rendering, so I guess I'll have to think of something more clever than a ref-counted texture..
Thanks
Bitwise
|
May 01, 2015 Re: Destruction in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise | On Thursday, 30 April 2015 at 23:27:49 UTC, bitwise wrote:
> Well, the third thing was just my reasoning for asking in the first place. I need to be able to acquire/release shared resources reliably, like an OpenGL texture, for example.
If you want to release resources, you are going to have to call some functions that do that for you, so you can't escape that "special stack frame"(what's so special about it?) - though the compiler might inline it.
When you use a GC the compiler don't need to invoke the destructor in the end of the scope because the object is destroyed in the background, but that also means you can't rely on it to release your resources, so languages like Java and C# use try-with-resources and using statements(corresponding) to call something at the end of the scope and end up using that stack frame anyways.
|
May 01, 2015 Re: Destruction in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Idan Arye | On Friday, 1 May 2015 at 02:35:52 UTC, Idan Arye wrote:
> On Thursday, 30 April 2015 at 23:27:49 UTC, bitwise wrote:
>> Well, the third thing was just my reasoning for asking in the first place. I need to be able to acquire/release shared resources reliably, like an OpenGL texture, for example.
>
> If you want to release resources, you are going to have to call some functions that do that for you, so you can't escape that "special stack frame"(what's so special about it?) - though the compiler might inline it.
>
> When you use a GC the compiler don't need to invoke the destructor in the end of the scope because the object is destroyed in the background, but that also means you can't rely on it to release your resources, so languages like Java and C# use try-with-resources and using statements(corresponding) to call something at the end of the scope and end up using that stack frame anyways.
I'm not sure I understand you 100%, but my plan was to have an asset management system give out ref counted textures/etc. Whenever the last one went out of scope, the asset would be destroyed. This only works if the destructor is called on the graphics thread due to limitations of graphics APIs. In a single threaded C++ app, this is fine, destructors are called at end of scope. I was confused though, because like C#, D has both reference and value types. But, while in C#, value types still do not have destructors(grrr...) D structs do have destructors, which apparently run when the struct goes out of scope. However, the D port of my code will most likely use multithreaded rendering, which removes the guarantee that the assets will go out of scope on the graphics thread, so this idea is a no-go anyways.
|
May 01, 2015 Re: Destruction in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to bitwise | On Friday, 1 May 2015 at 17:45:02 UTC, bitwise wrote: > On Friday, 1 May 2015 at 02:35:52 UTC, Idan Arye wrote: >> On Thursday, 30 April 2015 at 23:27:49 UTC, bitwise wrote: >>> Well, the third thing was just my reasoning for asking in the first place. I need to be able to acquire/release shared resources reliably, like an OpenGL texture, for example. >> >> If you want to release resources, you are going to have to call some functions that do that for you, so you can't escape that "special stack frame"(what's so special about it?) - though the compiler might inline it. >> >> When you use a GC the compiler don't need to invoke the destructor in the end of the scope because the object is destroyed in the background, but that also means you can't rely on it to release your resources, so languages like Java and C# use try-with-resources and using statements(corresponding) to call something at the end of the scope and end up using that stack frame anyways. > > I'm not sure I understand you 100%, but my plan was to have an asset management system give out ref counted textures/etc. Whenever the last one went out of scope, the asset would be destroyed. This only works if the destructor is called on the graphics thread due to limitations of graphics APIs. In a single threaded C++ app, this is fine, destructors are called at end of scope. I was confused though, because like C#, D has both reference and value types. But, while in C#, value types still do not have destructors(grrr...) D structs do have destructors, which apparently run when the struct goes out of scope. However, the D port of my code will most likely use multithreaded rendering, which removes the guarantee that the assets will go out of scope on the graphics thread, so this idea is a no-go anyways. Structs allow you to implement ref-counting smart pointers like you can do in C++. There is an implementation in the standard library: http://dlang.org/phobos/std_typecons.html#.RefCounted But for something as structured and as heavy as gaming resources, I would go for a more manual approach like a repository-style architecture, where you manually tell the repository to load/release the the resources. |
May 02, 2015 Re: Destruction in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Idan Arye | On Friday, 1 May 2015 at 18:37:41 UTC, Idan Arye wrote:
> On Friday, 1 May 2015 at 17:45:02 UTC, bitwise wrote:
>> On Friday, 1 May 2015 at 02:35:52 UTC, Idan Arye wrote:
>>> On Thursday, 30 April 2015 at 23:27:49 UTC, bitwise wrote:
>>>> Well, the third thing was just my reasoning for asking in the first place. I need to be able to acquire/release shared resources reliably, like an OpenGL texture, for example.
>>>
>>> If you want to release resources, you are going to have to call some functions that do that for you, so you can't escape that "special stack frame"(what's so special about it?) - though the compiler might inline it.
>>>
>>> When you use a GC the compiler don't need to invoke the destructor in the end of the scope because the object is destroyed in the background, but that also means you can't rely on it to release your resources, so languages like Java and C# use try-with-resources and using statements(corresponding) to call something at the end of the scope and end up using that stack frame anyways.
>>
>> I'm not sure I understand you 100%, but my plan was to have an asset management system give out ref counted textures/etc. Whenever the last one went out of scope, the asset would be destroyed. This only works if the destructor is called on the graphics thread due to limitations of graphics APIs. In a single threaded C++ app, this is fine, destructors are called at end of scope. I was confused though, because like C#, D has both reference and value types. But, while in C#, value types still do not have destructors(grrr...) D structs do have destructors, which apparently run when the struct goes out of scope. However, the D port of my code will most likely use multithreaded rendering, which removes the guarantee that the assets will go out of scope on the graphics thread, so this idea is a no-go anyways.
>
> Structs allow you to implement ref-counting smart pointers like you can do in C++. There is an implementation in the standard library: http://dlang.org/phobos/std_typecons.html#.RefCounted
>
> But for something as structured and as heavy as gaming resources, I would go for a more manual approach like a repository-style architecture, where you manually tell the repository to load/release the the resources.
A very easy and simple solution is to have a queue of unused
textures in your asset manager, that any thread can push to, but
only one thread consumes from. Whenever the last ref is released
you push a texture into this queue, and at the end of each frame,
while the GPU is busy rendering or flipping, you go through this
queue on the appropriate thread and delete the textures.
This has the advantage of making your timings deterministic, i.e.
a function won't suddently take 200x longer because it happened
to release the last ref to a texture.
Also, remember that aquiring/releasing refs in a threaded
environment is quite expensive, and you don't want to be doing
this while passing a texture around in your graphics pipeline, so
you probably shouldn't be counting texture refs at the texture
level, but maybe when you load/destroy a material, for example.
|
May 02, 2015 Re: Destruction in D | ||||
---|---|---|---|---|
| ||||
Posted in reply to Idan Arye | On Fri, 01 May 2015 14:37:40 -0400, Idan Arye <GenericNPC@gmail.com> wrote: > Structs allow you to implement ref-counting smart pointers like you can do in C++. There is an implementation in the standard library: http://dlang.org/phobos/std_typecons.html#.RefCounted Yeah, I guess I should have taken the existence of RefCounted as confirmation that D has deterministic destruction for structs, but the GC reference makes some pretty broad generalizations that do not seem to be entirely true. > But for something as structured and as heavy as gaming resources, I would go for a more manual approach like a repository-style architecture, where you manually tell the repository to load/release the the resources. A quick googling of "repository style architecture" yielded a large variety of pages, including a 143 slide presentation, which I have no intention of reading =/ I think such an architecture would be overkill for something like this. In any case, manually loading/releasing assets is a huge step backward. On Sat, 02 May 2015 09:22:57 -0400, Márcio Martins <MARCIOAPM@gmail.com> wrote: > A very easy and simple solution is to have a queue of unused > textures in your asset manager, that any thread can push to, but > only one thread consumes from. Whenever the last ref is released > you push a texture into this queue, and at the end of each frame, > while the GPU is busy rendering or flipping, you go through this > queue on the appropriate thread and delete the textures. > This has the advantage of making your timings deterministic, i.e. > a function won't suddently take 200x longer because it happened > to release the last ref to a texture. This sounds like it could work. > Also, remember that aquiring/releasing refs in a threaded > environment is quite expensive, and you don't want to be doing > this while passing a texture around in your graphics pipeline, so > you probably shouldn't be counting texture refs at the texture > level, but maybe when you load/destroy a material, for example. True. I was going to pass the RefCounted assets by (ref const), but the annoyance that brings hardly seems worth it at this point. I think I would wrap the assets in a class instead though, and let the destructor decrement a ref count in the asset manager instead of pushing it to a queue. That way, it would be at the discretion of the asset manager to destroy the assets as needed. At first, I would most likely destroy the assets immediately, but eventually, the destruction could be delayed until memory runs thin to cover awesome code like this: while(true) { Texture tex = Asset.GetTexture("card"); drawQuad(tex); } |
Copyright © 1999-2021 by the D Language Foundation