Resource Manager Pattern
In Embedded and Realtime Systems, there occur many instances of Resource
management. Most commonly used design pattern to manage resources of a specific
type is the Resource Manager Pattern. This pattern is described using a standard
pattern definition template.
This design pattern implementation uses STL (Standard Template Library), so
please review the following articles before this one:
Intent
The main intention here is to manage multiple resources of the same type. To
maintain the status of managed resources, a resource manager is implemented that
maintains two lists of resources. Free list contains all the resources that are
free. Busy list contains all the resources that are busy. A resource allocation
request is serviced by the resource manager by allocating a resource from the
free list and putting it in the busy list. Similarly, a resource release request
is serviced by the resource manager by inserting the freed resource to the free
list.
Also Known As
- Resource Allocator
- Resource Pool
Motivation
The resource manager design pattern implements a centralized management
strategy for resource usage. Looking at the free and busy lists of resources
gives a clear picture of the current resource usage in the system. Using the
resource manager, the application can quickly figure out all allocated resources
in the system. This information helps in implementing audits also.
Applicability
The resource manager design pattern finds applicability in situations where
centralized management of multiple resources of same type is involved.
Structure
The resource manager keeps two lists, one for busy resources and one for free
resources. Internally the free list may be maintained as a stack if hottest
resource first type of scenario needs to be implemented. If a coldest resource
first type of scenario is to be implemented, the free list may be maintained as
a queue. The busy list is maintained as a STL map so that resources can be
quickly accessed. (The map is keyed with the resource-id, a unique number
assigned to every resource)
Participants
The key actors of this design pattern:
- Resource Manager: Manages all free and busy
resources using the free queue and busy map.
- Free Resource Queue: Keeps track of free
resources in a STL queue.
- Busy Resource Map: Manages the busy resources
in a STL map.
- Resource: Defines a resource object with its
own resource-id.
Collaboration
The following diagram shows the relationship and collaboration between
various classes involved in the Resource Manager Pattern. Points to note
are:
- Resource Manager contains the Free Resource Queue and the Busy Resource
Map
- Free Resource Queue and Busy Resource Map contain Resource objects
- Resources are directly allocated from the Resource Manager. The user of
the class is not aware of its internal structure as a free and busy
lists.
Consequences
When Resource Manager Pattern is used, the programmer always has access to
all the resources. Thus any action on resources can be initiated from the
Resource Manager, instead of handling it separately in all objects that allocate
resources.
Implementation
The following scenarios are supported by the Resource Manager:
Allocating a Resource
- A system entity sends a request for a resource to resource manager.
- The resource manager allocates a resource from the FreeResourceQueue.
- The resource manager removes the resource from the FreeResourceQueue.
- The resource manager adds the resource to the BusyResourceMap.
- The resource manager responds to system entity with the pointer of the
allocated resource.
Freeing a Resource
- A system entity sends a resource release request to the resource manager.
- The resource manager removes the resource from the BusyResourceMap.
- The resource manager adds the resource to the FreeResourceQueue.
Adding a Resource
- When a resource is created, it is added to the FreeResourceQueue.
Removing a Resource
- Check if the resource is present in the BusyResourceMap.
- If the resource is present, inform resource about the forced release (if
the resource is currently in use, the application using the resource needs to
be notified)
- Remove the resource from the BusyResourceMap.
- If the resource is not present in the BusyResourceMap, remove the resource
from the FreeResourceQueue.
Sample Code and Usage
Here is the code for a typical implementation of this pattern using STL:
Resource
Manager |
#include <queue> // STL header file for queue
#include <map> // Header file for map
using namespace std; // Specify that we are using the std namespace
// Resource Id: A unique id assigned to every resource
typedef int ResourceId;
class ResourceManager
{
// Declaring the type for a queue. Here we are specifying
// a queue of Resource pointers organized as a linked list.
typedef queue<Resource *>, list<Resource *> > FreeResourceQueue;
FreeResourceQueue m_freeResourceQueue;
// Map is used to keep track of the busy resources.
typedef map <Resource *, ResourceId> BusyResourceMap;
BusyResourceMap m_busyResourceMap;
public:
ResourceManager(int resourceCount, Resource *resourceArray)
{
// Add all the resources that have been specified at construction time
for (int i = 0; i < resourceCount; i++)
{
Add(resourceArray[i]);
}
}
// Allocate a free resource by removing it from the
// the free resource queue. Returns NULL if no resource is found
Resource * Allocate()
{
Resource *pResource = NULL;
// Check if any free resources are available.
if (!m_freeResourceQueue.empty())
{
// Queue is not empty so get a pointer to the
// first resource in the queue
pResource = m_freeResourceQueue.front();
// Now remove the pointer from the free resource queue
m_freeResourceQueue.pop();
// Next step is to add the resource to the busy map ...
// Obtain the resource id
ResourceId resId = pResource->GetResourceId();
// Make sure that the resource is not already present in the map
if (m_busyResourceMap.count(resId) == 0)
{
m_busyResourceMap[resId] = pResource;
}
}
return pResource;
}
// Free a resource by adding it back into the free resource list
void Free(Resource *pResource)
{
// Obtain the resource Id
ResourceId resId = pResource->GetResourceId();
// Remove the resource from the busy resource map
m_busyResourceMap.erase(resId);
// Insert the resource at the end of the free queue
m_freeResourceQueue.push(pResource);
}
// Obtain the total count of free resources
int GetFreeResourceCount() const
{
return m_freeResourceQueue.size();
}
int GetBusyResourceCount() const
{
return m_busyResourceMap.size();
}
// Adding a new resource to the resource manager.
void Add(Resource *pResource)
{
// A new resource is assumed to be free, hence it is
// added to the free queue
m_freeResourceQueue.push(pResource);
}
// Remove the resource from the resource manager
void Remove(Resource *pResource)
{
// Obtain the resource id
ResourceId resId = pResource->GetResourceId();
// Check if the resource is present in the map
// i.e. the resource is currently busy
if (m_busyResourceMap.count(resId))
{
// This resource is currently in use, so inform
// the Resource object about this release. Resource
// will inform the application about the forced release
pResource->HandleForcedRelease();
// Remove the resource from the busy resource map
m_busyResourceMap.erase(resId);
}
else
{
// remove the pointer from the free resource queue
m_freeResourceQueue.erase(resId);
}
}
};
|
Known Uses
Any application where resources need to be managed. A few examples of a
Resource Manager use are:
- Timeslot Manager
- Orbit Manager
- Terminal Manager
Related Patterns