Re: Can I remove an element from a global associative array from within a class destructor?

2019-08-03 Thread JN via Digitalmars-d-learn

On Friday, 2 August 2019 at 23:13:10 UTC, realhet wrote:
Today I read the documentation about structs, unions and 
classes, but I haven't find any restrictions for the ~this() 
destructors.


Is there some extra rules regarding the GC and what I must not 
do in the destructors?


Class destructors are similar to Java's finalizers in behavior. D 
doesn't give you a guarantee when the class destructor is called 
and it doesn't give you a guarantee if it will be called at all, 
so it doesn't really work for RAII-like resource management. If 
you want RAII-like behavior, either use structs (struct 
destructors are deterministic), or wrap your class inside a 
scoped/refCounted wrapper from std.typecons.


Re: Can I remove an element from a global associative array from within a class destructor?

2019-08-03 Thread realhet via Digitalmars-d-learn
On Saturday, 3 August 2019 at 05:33:05 UTC, Jonathan M Davis 
wrote:
On Friday, August 2, 2019 5:13:10 PM MDT realhet via 
Digitalmars-d-learn wrote:

Hi,
...


Thank you!

Now I have 2 solutions in mind:
1. If I only want to track the count and totalBytes for a 
specific kind of reference, I will be able update those from the 
destructor.
2. If I wanna track all instances of resources, I will use 2 
classes instead of one class and an associative array:
- When I create a resource, I create class1 for the statistics, 
and store them in an assocArray. Then I create a class2 and 
inside it there is a reference to class1. Class2 will be given to 
the user. If the user don't use it anymore, the GC will destroy 
class2, and in it's destructor it will mark a field in class1. 
And it will be periodically checked, so the actual deletion of 
the GLBuffer and other statistics will be done by me.
With millions of resources it will be slow, but for a few 
thousand it's ok. (I can also put them in a hierarchy, but the 
most important is not to alloc/dealloc from ~this())


I hope it will be stable :D

Thank You again!




Re: Can I remove an element from a global associative array from within a class destructor?

2019-08-02 Thread Jonathan M Davis via Digitalmars-d-learn
On Friday, August 2, 2019 5:13:10 PM MDT realhet via Digitalmars-d-learn 
wrote:
> Hi,
>
> I tried to make some resource statistict for my OpenGL Buffer
> objects:
>
>
> //here are the things that hold the statistics.
> private __gshared{ size_t[int] textureSizeMap, bufferSizeMap; }
>
> struct GLCounters{
>int programs, shaders, textures, buffers;
>size_t textureSize, bufferSize;
> }
> __gshared GLCounters glCounters;
>
> ...
>
> //And this is the buffer creation.
> int genBuffer(size_t size){
>int res; glGenBuffers (1, &res); glChk;
>glCounters.buffers ++;
>glCounters.bufferSize  += size;
>bufferSizeMap [res] = size;
>writefln("buffer allocated %d %d", res, size);
>return res;
> }
>
> //Finally, this is the deallocation. If it is called from the GC
> (when it destroys a class), it has a big chance to throw an
> Invalid Memory Operation exception.
>
> void deleteBuffer (int handle){
>if(!handle) return;
>glDeleteBuffers (1, &handle); glChk;
>glCounters.buffers --;
>glCounters.bufferSize  -= bufferSizeMap [handle];
>writefln("buffer deallocated %d %d", handle, bufferSizeMap
> [handle]);
>bufferSizeMap.remove(handle); <- this is the problematic part.
> }
>
> 
> Today I read the documentation about structs, unions and classes,
> but I haven't find any restrictions for the ~this() destructors.
>
> Is there some extra rules regarding the GC and what I must not do
> in the destructors?
>
> I think the destructor always called in the same thread where the
> instance was created. This can't be the case.
> But what I can guess is: The GC makes a collection and calls my
> destructor and inside I do something and the GC calls a
> collection again recursively. But it seems a bit crazy, so I
> think it's not the case :D
>
> Please help me solve this!
>
> *I'm using LDC 1.6.0 Win64

As I understand it, you can't do much of anything that involves the GC
inside a destructor that's being run as a finalizer by the GC (as is almost
always the case with classes). Structs or classes on the stack (which for
classes requires something like scope) don't have that problem, because
they're not being run by the GC. But if a struct or class is on the GC heap,
then attempting to allocate or deallocate GC resources doesn't work, because
the destructor/finalizer runs when the GC is doing a collection. Even trying
to use other objects that are on the GC heap from a finalizer is not a
allowed, because there is no guarantee about the order that the objects are
collected (otherwise, cyclical references would be a big problem), meaning
that references in the finalizer could refer to objects that have already
been destroyed and their memory freed.

https://dlang.org/spec/class.html#destructors

Basically, destructors/finalizers for anything on the GC heap are just for
cleaning up non-GC-allocated resources.

- Jonathan M Davis





Can I remove an element from a global associative array from within a class destructor?

2019-08-02 Thread realhet via Digitalmars-d-learn

Hi,

I tried to make some resource statistict for my OpenGL Buffer 
objects:



//here are the things that hold the statistics.
private __gshared{ size_t[int] textureSizeMap, bufferSizeMap; }

struct GLCounters{
  int programs, shaders, textures, buffers;
  size_t textureSize, bufferSize;
}
__gshared GLCounters glCounters;

...

//And this is the buffer creation.
int genBuffer(size_t size){
  int res; glGenBuffers (1, &res); glChk;
  glCounters.buffers ++;
  glCounters.bufferSize  += size;
  bufferSizeMap [res] = size;
  writefln("buffer allocated %d %d", res, size);
  return res;
}

//Finally, this is the deallocation. If it is called from the GC 
(when it destroys a class), it has a big chance to throw an 
Invalid Memory Operation exception.


void deleteBuffer (int handle){
  if(!handle) return;
  glDeleteBuffers (1, &handle); glChk;
  glCounters.buffers --;
  glCounters.bufferSize  -= bufferSizeMap [handle];
  writefln("buffer deallocated %d %d", handle, bufferSizeMap 
[handle]);

  bufferSizeMap.remove(handle); <- this is the problematic part.
}


Today I read the documentation about structs, unions and classes, 
but I haven't find any restrictions for the ~this() destructors.


Is there some extra rules regarding the GC and what I must not do 
in the destructors?


I think the destructor always called in the same thread where the 
instance was created. This can't be the case.
But what I can guess is: The GC makes a collection and calls my 
destructor and inside I do something and the GC calls a 
collection again recursively. But it seems a bit crazy, so I 
think it's not the case :D


Please help me solve this!

*I'm using LDC 1.6.0 Win64