Well after arguing and doing nothing else today, I started to recreate my Resource Management system.
I replaced the reference counting with boost::shared_ptr, however I can't figure out one thing.
Someone want to create a resource, he uses the appropriate resource manager (be it texture manager, or mesh manager), the resource is created inside the manager and have 1 reference to it, and right then it returned to the one who initiated the creation of it and this changes the reference to 2 (one reference held by the manager and another one by the initiator of the resource creation). During the runtime others would like to use the same resource, and resources reference will go up and down, until everyone who wanted to use the resource do not use it anymore, leaving it with count of 1 (only resource manager holds the reference now).
In this situation resource manager can not know that the resource is not shared anymore and can be freed. This is not the behavior I wish.
I probably mistaken here, but as far as I know no game load all its resources to memory, its loaded per level.
So I thought about loading needed stuff with level loading, and unload when level switched.
Anyone have any idea how I could implement this?
Thanks again.
A note on resources and managers, why it is so hard to write a good one?
Quote:Original post by s.kwee
You would break any reason Ill give
Yes, that's the point; so you can learn something. Stubbornness is not a good trait for programmers in general. (Not to be confused with persistence, which is often useful.)
Quote:and I don't want this topic to become a holy-war of using or not using stl/boost.
A "holy war of using or not using stl/boost" would be sort of like a holy war over whether or not to brush your teeth.
And it's not "STL" any more. We're not talking about a third-party library. We're talking about the standard library of the language you are using. You can no more ignore std::string in C++ than you can ignore strlen() in C. (And FWIW, there are parts of the original STL that didn't make the cut for the C++ standard library. Though in most cases I wish it had.)
Quote:No I'm not anti STL, and next time when you meaning the shared_ptr that is included in the standard library please say std/stl share_ptr and not boost. And I didn't know that shared_ptr was boosts, and I rarely used it.
jyk is talking about C++0x which is not commonly supported yet. The point is that it's coming, whether you like it or not.
Quote:Have you ever asked your self why some courses teach you algorithms and data structures? Trying to recreate C++'s functionality via C?
Yes, and I still ask myself, after having gone through it and having heard all the arguments for doing so, many, many times.
Quote:but when you implement your own
When?
Quote:you actually think "sort? how to sort? what is the best sort? how should I sort list?" "Reverse? how I can reverse list?".
That's a good thing, though. If anything, people who do end up having to care about these things should be made to think about them, instead of being spoon-fed by a professor.
Quote:what I do care is to understand why it works like this and when I know how it works,
And do you really feel that you have to implement it to understand it? What's wrong with reading a high-level description? Such as the one provided by the Boost documentation?
Quote:Original post by s.kweeIs shared_ptr::unique() what you're looking for?
Well after arguing and doing nothing else today, I started to recreate my Resource Management system.
I replaced the reference counting with boost::shared_ptr, however I can't figure out one thing.
Someone want to create a resource, he uses the appropriate resource manager (be it texture manager, or mesh manager), the resource is created inside the manager and have 1 reference to it, and right then it returned to the one who initiated the creation of it and this changes the reference to 2 (one reference held by the manager and another one by the initiator of the resource creation). During the runtime others would like to use the same resource, and resources reference will go up and down, until everyone who wanted to use the resource do not use it anymore, leaving it with count of 1 (only resource manager holds the reference now).
In this situation resource manager can not know that the resource is not shared anymore and can be freed. This is not the behavior I wish.
I probably mistaken here, but as far as I know no game load all its resources to memory, its loaded per level.
So I thought about loading needed stuff with level loading, and unload when level switched.
Anyone have any idea how I could implement this?
Thanks again.
Zahlman
Thank you for the comment, but I already understood my mistakes, and agree with what you said :)
jyk
Ok, but how I can notify the manager that the last resource released? The only way I see is calling X time units a function that will run on the resource manager managed resources hash table and will check for resources that are unique and will free them.
Thank you for the comment, but I already understood my mistakes, and agree with what you said :)
jyk
Ok, but how I can notify the manager that the last resource released? The only way I see is calling X time units a function that will run on the resource manager managed resources hash table and will check for resources that are unique and will free them.
I mentioned this briefly in one of my earlier posts.
What I have is a method called "collect" which walks through the table of resources and ejects resources who's reference count is just 1 -- I use the unique() method of the shared_ptr to determine if the reference count is 1.
Another version of collect() can optionally force ejection from the manager by setting its "force" parameter to true -- in which case the resource is ejected, regardless of its count. When this happens, the resource data is not actually destroyed until the last reference to it is deleted or goes out of scope. If the client requests to re-acquire that same resource again, a new resource instance is created, regardless of whether or not the old instance is still around, because there is just no way to know.
In general, you're going to want to call collect at known times (such as between frames or levels, when performance isn't critical), so I haven't done any work to specifically make my manager thread-safe, but I imagine it wouldn't be that difficult. With thread-safe support in place, one could spawn a new thread that would call collect periodically -- making the system more akin to active garbage collection.
Also, my resource system actually has an internal class ResourceMetaInfo, which wraps the ResourceInfo type, and which contains some additional information. Currently, this additional information amounts to a storage class specifier for resources. I have three storage classes for resources PERMANANT, TEMPORARY and MOMENTARY. PERMANANT resources aren't deleted unless "force" is set to true -- this is intended for system-wide resources (like menu graphics which must always be at the ready, for instance). TEMPORARY resources are not deleted when the refcount is 1 unless memory needs to be freed up (unless forced) and are intended for level-wide resources. MOMENTARY resources are those which are only likely to be needed for a frame or so, and are always deleted when the refcount is 1.
Hope that helps, feel free to ask any more questions you may have.
What I have is a method called "collect" which walks through the table of resources and ejects resources who's reference count is just 1 -- I use the unique() method of the shared_ptr to determine if the reference count is 1.
Another version of collect() can optionally force ejection from the manager by setting its "force" parameter to true -- in which case the resource is ejected, regardless of its count. When this happens, the resource data is not actually destroyed until the last reference to it is deleted or goes out of scope. If the client requests to re-acquire that same resource again, a new resource instance is created, regardless of whether or not the old instance is still around, because there is just no way to know.
In general, you're going to want to call collect at known times (such as between frames or levels, when performance isn't critical), so I haven't done any work to specifically make my manager thread-safe, but I imagine it wouldn't be that difficult. With thread-safe support in place, one could spawn a new thread that would call collect periodically -- making the system more akin to active garbage collection.
Also, my resource system actually has an internal class ResourceMetaInfo, which wraps the ResourceInfo type, and which contains some additional information. Currently, this additional information amounts to a storage class specifier for resources. I have three storage classes for resources PERMANANT, TEMPORARY and MOMENTARY. PERMANANT resources aren't deleted unless "force" is set to true -- this is intended for system-wide resources (like menu graphics which must always be at the ready, for instance). TEMPORARY resources are not deleted when the refcount is 1 unless memory needs to be freed up (unless forced) and are intended for level-wide resources. MOMENTARY resources are those which are only likely to be needed for a frame or so, and are always deleted when the refcount is 1.
Hope that helps, feel free to ask any more questions you may have.
Quote:Original post by s.kwee
Anyone have any idea how I could implement this?
boost::weak_ptr
shared_ptr and weak_ptr work together. If only weak_ptrs point to a resource, it's deleted/collected.
In my old C++ manager, I had the manager keep weak_ptrs, and then give out shared_ptrs. When the rest of the game stopped using the resource, it went out of memory without the manager caring (until it loaded the resource again). For my needs it was great. Different requirements (clear resources based on memory usage,clear resources based on level, etc.) will of course require different solutions.
unique() indicates that there is only one reference - or use_count() will give you a count of outstanding references. Using this information would allow you to periodically sweep and delete the already deallocated resource from the holding collection.
Alternatively for your collection use weak_ptr's but pass out shared_ptr's and then in the destructor (or custom deleter) of the resource fire an event (ie drop()) which the collection could hook to erase it automatically.
Alternatively use an boost intrusive pointer (weak_ptr's dont work with it) and manually adjust the ref_count to account for the additional reference maintained by the collection (eg decrement). Then do the periodic sweep and delete.
Alternatively for your collection use weak_ptr's but pass out shared_ptr's and then in the destructor (or custom deleter) of the resource fire an event (ie drop()) which the collection could hook to erase it automatically.
Alternatively use an boost intrusive pointer (weak_ptr's dont work with it) and manually adjust the ref_count to account for the additional reference maintained by the collection (eg decrement). Then do the periodic sweep and delete.
Ravyne
Yea, what I mentioned, now after thinking a bit more about this method it looks good, Ill probably will go with it.
Telastyn
This is nice! It really does what I need! Thanks!
chairthrower
In boosts documentation said that use_count() is not recommended to use in production code, anyway unique will be enough to determine that the resource is not used anymore.
Thanks ever body I think I finally got it :)
Yea, what I mentioned, now after thinking a bit more about this method it looks good, Ill probably will go with it.
Telastyn
This is nice! It really does what I need! Thanks!
chairthrower
In boosts documentation said that use_count() is not recommended to use in production code, anyway unique will be enough to determine that the resource is not used anymore.
Thanks ever body I think I finally got it :)
Gotta play Devil's Advocate here, for those who aren't fans of complexity for complexity's sake.
I refer to my resources by string name. Or index into a lookup table if I need more performance.
This way I don't need to "manage" them at all. Caching, loading, and unloading are all handled behind the scenes.
I refer to my resources by string name. Or index into a lookup table if I need more performance.
This way I don't need to "manage" them at all. Caching, loading, and unloading are all handled behind the scenes.
Action("aresource", parameters);
Done.
Quote:Original post by CadetUmfer
Gotta play Devil's Advocate here, for those who aren't fans of complexity for complexity's sake.
I refer to my resources by string name. Or index into a lookup table if I need more performance.
This way I don't need to "manage" them at all. Caching, loading, and unloading are all handled behind the scenes.Done.Action("aresource", parameters);
Care to clarify? That example doesn't exactly spell out what you're doing differently/better.
This topic is closed to new replies.
Advertisement
Popular Topics
Advertisement