Issott_Common Design Patterns for Symbian OS-The Foundations of Smartphone Software_0470516356 (779879), страница 16
Текст из файла (страница 16)
The lazy allocator is then free to determine the best lifetime ofthe resource, removing the need for the resource client to check if thelazy allocator is ready for use.66RESOURCE LIFETIMESDynamicsWhen initialized, the resource client creates a lazy allocator object,which it uses for all the requests that would otherwise have been madedirectly on the resource (see Figure 3.4). It is only when the resource clientfirst makes a call to the lazy allocator which requires the resource thatthe resource is actually allocated. Subsequent calls to the lazy allocatorobject are passed straight to the already allocated resource.ImplementationIn this chapter, C classes are used to demonstrate the implementation though it would be possible to use R classes instead with fewchanges. Also, for simplicity, error handling is done using Escalate Errors(see page 32) although an alternative error-handling strategy could beused.ResourceThe following code simply defines the resource we will be using:class CResource : public CBase{public:// Performs some operation and Leaves if an error occursTInt UseL();}Resource ProviderHere is the resource provider we will be using:class CResourceProvider : public CBase{public:// Allocates and returns a new CResource object.
If an error occurs,// it Leaves with a standard Symbian error code.static CResource* AllocateL(TInt aParam);// Matching de-allocatorstatic void Deallocate(CResource* aResource);}Lazy AllocatorThis Proxy object simply checks if its resource has been allocated, beforecalling the appropriate function on it. Since it is a Proxy, it must provideall the methods that the resource provides, in addition to the methodsused to create the lazy allocator.LAZY ALLOCATION67Resource ProviderResource Clientseq InitializationConstructL()Lazy Allocator()constructor()seq First UseUseL()AllocateL()Resourceconstructor()UseL()seq Subsequent UseUseL()UseL()seq Destructiondestructor()Deallocate()destructor()Figure 3.4 Dynamics of the Lazy Allocation pattern68RESOURCE LIFETIMESclass CLazyAllocator : public CBase{public:CLazyAllocator(TInt aAllocParam);∼CLazyAllocator();// CResource functionsvoid UseL();private:void InitializeResourceIfNeededL();private:TInt iAllocParam;CResource* iResource;};The constructor needs to take the information needed to allocate theresource as parameters and remember it until later:CLazyAllocator::CLazyAllocator(TInt aAllocParam): iAllocParam(aAllocParam){}The destructor just needs to de-allocate the resource if it has beenallocated.
Note that CResourceProvider::Deallocate() shouldbe used rather than deleting the resource directly since it allows theresource provider to choose how to deal with the resource. For instance,it may wish to keep the object and re-use it later.CLazyAllocator::∼CLazyAllocator(){if (iResource){CResourceProvider::Deallocate(iResource);}}The private InitializeResourceIfNeededL() method is alsostraightforward. It first checks if the resource has been allocated and onlyallocates it if it hasn’t:void CLazyAllocator::InitializeResourceIfNeededL(){if(iResource == NULL){iResource = CResourceProvider::AllocateL(iAllocParam);}}LAZY ALLOCATION69The following implementation of CLazyAllocator::UseL() simply ensures the resource has been allocated before going on touse it:void CLazyAllocator::UseL(){InitializeResourceIfNeededL();iResource->UseL();}However, the problem comes when you are dealing with a resourcefunction that doesn’t return an error.
The resource allocator functionshave to be able to return an error since any one of them could be the firstfunction called, attempt to allocate the resource and fail to do so. Thismeans the resource allocator may not be able to provide a completelyidentical interface to the one provided by the resource.ConsequencesPositives• Improves start-up time since resources are not allocated until they’reneeded. Since allocation occurs at the point of use, the time takento allocate your resources occurs throughout the lifetime of yourcomponent, instead of occurring all at once.• Reduces resource usage across the system since you only allocate theresources which are actually used.• Simplifies the resource client by removing the need to check if theresource has been allocated before use.Negatives• Maintenance costs are increased because each use of the resourcecan fail and hence there are more error paths to deal with whichmakes your component more complex compared to using Immortal(see page 53).• The cost of testing is increased due to the unpredictability of when theresource is actually allocated and the increased error costs comparedto using Immortal (see page 53).
Whilst it’s true that the allocationis on first use, this doesn’t provide much of a constraint on thebehavior.• This pattern is unlikely to be suitable for resources used in realtime operations as, for many resources, allocation is an unboundedoperation. Use of a lazy allocator could trigger an allocation for anyuse of the resource and break your real-time constraints.70RESOURCE LIFETIMES• The use of resources slowly grows over time since they are deallocated only when the resource client decides the resource isno longer needed, which might be when the whole componentis unloaded. However, this problem can be addressed using otherpatterns such as Lazy De-allocation (see page 73).Example ResolvedSince Symbian OS v9.2, the Comms-Infras has supported the on-demandloading of CPMs under certain configurations.During the initialization of Comms-Infras, an INI file is read for eachCPM.
The INI file specifies the CPM’s configuration options includingwhether it should be loaded on demand. If the CPM is to be loadedon demand then a simple proxy object, CModuleRef (the lazy allocator), containing a pointer to the CPM is created. This lazy allocatorobject is added to the list of available CPMs within Comms-Infras.However, each CPM is only allocated and initialized when it is firstused.In this example, each CPM is it its own resource provider as well asa resource.Other Known UsesThis pattern is used throughout Symbian OS and here are just some of themany examples:• Image convertersThe Image Conversion Library (ICL) framework only loads specificconverters for specific image types (GIF, JPEG, etc.) when the conversion of an image of the corresponding type is requested by aclient.• FontsThe font and bitmap server only loads and renders fonts into memorywhen they are first requested.
This is a particularly important useof this pattern when you consider that it is unlikely that all of thenumerous fonts will be used all the time and that there might be fontsfor different character sets (e.g. Latin, Greek or Kanji) that an end usermight never use.• Transient serversThese are only loaded when a client first connects to them. Theyare a common occurrence in Symbian OS. Examples are the Contacts Engine, Agenda Model and Messaging server, though whetherthey exhibit this behavior is configurable. For more information, seeClient–Server on page 182.LAZY ALLOCATION71Variants and Extensions• Idle ObjectThis is a middle ground between immediate allocation of resourcesand lazy allocation.
You start the process of resource allocation afteror even during initialization of your component but only allow it tohappen when your thread is not busy (see Figure 3.5).ResourceResource ClientAllocate()Busy()Initialize()Busy()Initialize()ResourceAllocated()Figure 3.5Dynamics of the Idle Object patternThis is often used in situations where you know the non-essentialresource is going to be used eventually but the resource client canstart operating without it.It is often implemented by using a CIdle-derived active object insituations where the creation and initialization of the resource is timeintensive. The derivation from CIdle is a convenient way of deprioritizing the initialization of the resource relative to your thread’sother active objects.1010 CIdleworks well here if you assign it the lowest possible active object priority.72RESOURCE LIFETIMESReferences• Immortal (see page 53) is an alternative resource lifetime pattern.• Lazy De-allocation (see page 73) extends this pattern to de-allocateobjects intelligently.• Escalate Errors (see page 32) is used to handle allocation errors withinthe lazy allocator so that the resource client has the choice of whetherto handle these errors or not.• Proxy [Gamma et al., 1994] is used to implement the lazy allocator.• Lazy Acquisition [Kircher and Jain, 2004] covers similar ground withinthe context of other environments.LAZY DE-ALLOCATION73Lazy De-allocationIntentDelay the de-allocation of a resource so that an almost immediate re-useof the resource does not incur a performance penalty.AKADelayed Unloading, Lazy UnloadingProblemContextA resource which is expensive to allocate or de-allocate is used frequentlySummary• The resources you are interested in are scarce and need to be sharedacross the system.• The use of the resource comes in bursts so that if it is used once thereis a good chance it’ll be used again soon.• You need to provide quick responses and so need to avoid having toallocate a resource whenever possible.DescriptionAs has been repeated many times throughout this book, an open mobiledevice has a number of constraints that don’t affect a PC; in comparison,a PC has almost limitless resources.
Mobile devices are also differentfrom small embedded systems such as microwaves and personal videorecorders, which have similar, if not stricter, resource constraints. However, they are not expected to be multi-tasking nor to allow the installationof new applications or services which is a key requirement of an opendevice. Hence when you are developing software for Symbian you needto be a ‘good citizen’ and cooperate with the other components on adevice by sharing resources well.Part of being a ‘good citizen’ is to de-allocate resources that you haveallocated when they are no longer needed. While this is most commonlytrue of allocations of memory, it is also true of other resources.
Forexample, if your component allocates a radio communication channeland does not de-allocate the connection resource when it has finishedusing it then other components may be prevented from using the radiocommunication channel for a different purpose.This understanding combined with a desire to make your applicationor service cooperate well with other software on the device should lead74RESOURCE LIFETIMESyou to consider a Mayfly approach and de-allocate resources as soonas they’re no longer required.