Issott_Common Design Patterns for Symbian OS-The Foundations of Smartphone Software_0470516356 (779879), страница 18
Текст из файла (страница 18)
To decide upon the bestvalue for the timeout you should first consider the use cases for theLAZY DE-ALLOCATION81allocation and de-allocation of the resources by obtaining logs showingresource allocation and de-allocation to observe your usage patterns.After this, an informed decision can be made about the value to use forthe timeout. If it is too long, such as hours perhaps, then the resourcemight never be de-allocated, but if it is too short, such as a millisecond,then the resource may be de-allocated after every use.By isolating the timeout value into a single constant, it is very straightforward to change the timeout value at a later stage.
You are likely towant to be able to change the timeout once the dynamic behavior hasbeen observed in a running system or to fine tune future versions of yoursoftware. Isolating the timeout into a single constant makes this adjustment far easier. You might even find it useful to determine the timeoutwhen constructing the lazy de-allocator at run time, such as by reading avalue from the Central Repository.The following implementation of CLazyDeallocator::Use() simply forwards the function call on to the resource:void CLazyDeallocator::Use(){// Panic if the client hasn’t called PrepareResourceL()ASSERT(iResource);iResource->Use();}When the timer expires, the CLazyDeallocator::RunL() implementation is run to de-allocate the resource:void CLazyDeallocator::RunL(){User::LeaveIfError(iStatus.Int());CResourceProvider::Deallocate(iResource);iResource = NULL;}The implementation of CLazyDeallocator::RunError() is leftout for clarity.
No CLazyDeallocator::DoCancel() function isneeded either, since it’s provided by CTimer.Resource ClientWhenever the resource client is first constructed, it creates itself a CLazyDeallocator object for use later:void CResourceClient::ConstructL(){iResourceProxy = CLazyDeallocator::NewL();}82RESOURCE LIFETIMESHowever, when the resource client actually wants to use the resource,it does so by letting the CLazyDeallocator object know when and forhow long by calling first PrepareResourceL() and then ReleaseResource(). The resource client should use these functions as frequently as possible so that the CLazyDeallocator object is able to keepan accurate track of when the underlying resource is actually being used:void CResourceClient::DoOperationL(){iResourceProxy->PrepareResourceL();// Perform required actions with resourceiResourceProxy->Use();...iLazyUnloader.ReleaseResource();}ConsequencesPositives• There is better sharing of resource within the system when comparedwith more ‘greedy’ allocation strategies such as Immortal (see page 53).• Less time is wasted in repeatedly allocating frequently used resources – one resource is allocated and reused, allowing your component to be more responsive.• Your software is simplified – the responsibility for optimizing theresource lifetime is in one place rather than spread out across a wholecomponent.• The resource client is still able to control when a resource is available,and hence the (de-)allocation error paths, by calling CLazyDeallocator::PrepareResourceL().Negatives• Resource use is unpredictable – there is no direct control over thenumber of resources allocated at one time which could lead to aresource shortage while waiting for the de-allocation callbacks forunused resources to run.• Testing a component using this pattern may become more difficultbecause of the unpredictability of its resource usage.• The de-allocation callback uses additional resources – in the implementation above, this was the timer.
This pattern is only good forsituations where the resources being managed are significantly moreexpensive than the resources needed for the de-allocation callbacks.LAZY DE-ALLOCATION83• This pattern is not suitable if the resource is very frequently used – inthese cases the de-allocation callback will rarely, if ever, expire as itwill be reset after every use.
This leads to extra complexity for no gainas the resource is never out of use for long enough to be de-allocated.For this situation, Immortal (see page 53) would be more suitable.Example ResolvedThe recognizer framework uses this pattern to solve the problem of how tohandle the allocation and de-allocation of individual recognizer plug-ins.This was introduced in Symbian OS v9.1 as a way to reduce the RAMused by a device as well as providing performance optimization so thatthe recognizer framework, and hence the device, would start up morequickly. To preserve compatibility, this behavior was made configurableat ROM build time.The recognizer framework uses a timer as its strategy for determiningwhen to run the de-allocation callback with a timeout of 10 seconds bydefault. However, because the use of recognizers will vary from deviceto device, this timeout was also made configurable at ROM build time.By applying this pattern, it was possible to solve both problems: freeingthe resources used by the recognizers for the majority of the time whilepreserving an acceptable level of performance in use cases where therecognizers are heavily used.Other Known Uses• Transient serversMany servers are only started when needed by implementing thispattern.
Instead of closing completely when the last client disconnectsa timer is started. If a new connection to the server happens duringthe timer period then it is canceled and the server’s destruction isaborted. The messaging server is one such example.13• Audio Video Distribution Transport ProtocolThe AVDTP uses this pattern to avoid the high cost of tearing downand then re-establishing a Bluetooth connection unless absolutelynecessary. This is done by using a timer that is only started once thelast client of the protocol has disconnected.Variants and Extensions• Automatic Lazy Resource ProxyIn this variant, the resource client doesn’t tell the lazy de-allocatorwhen it is using a resource by calling PrepareResourceL() or13 Insome configurations.84RESOURCE LIFETIMESReleaseResource().
Instead, it simply calls one of the resourcefunctions that the lazy de-allocator provides as a proxy for the resourceand the lazy de-allocator ensures a resource is available to meet therequest.This is done by checking if the resource is allocated at the start ofeach resource operation exposed by the lazy resource and starting ade-allocation callback at the end of every method, which would looksomething like this:void CLazyResource::UseL(){if(!iResource){iResource = CResourceProvider::AllocateL();}// Perform requested actioniResource->Use();// Start the timer for the iResource de-allocation callbackif (!IsActive()){After(KDeallocTimeout);}}This approach combines both Lazy Allocation (see page 63) and LazyDe-allocation into a single pattern.• Pooled Allocation [Weir and Noble, 2000]In this variant, a group of resources is allocated by a resource provideras soon as it is created.
These resources are owned by the resourceprovider until a resource client makes an allocation. This allocationis immediately satisfied from the resource pool, if a resource isavailable, otherwise a full allocation occurs to satisfy the request.When a resource is de-allocated, it is returned to the resource poolunless the pool has already reached a fixed size, at which point it isdestroyed.
It is only when the resource provider itself is destroyed thatall the resources in the resource pool are de-allocated.References• Immortal (see page 53) describes an alternative approach to managingresource lifetimes.• Lazy Allocation (see page 63) is often combined with this pattern.• Pooled Allocation [Weir and Noble, 2000] describes a variation ofthis pattern.LAZY DE-ALLOCATION85• Pooling [Kircher and Jain, 2004] is a pattern similar to Pooled Allocation.• Leasing [Kircher and Jain, 2004] is a pattern that allows a ResourceLifecycle Manager to specify the time for which the resources areavailable.• Evictor [Kircher and Jain, 2004] is a pattern that allows for thecontrolled removal of less frequently used resources from a cache.4Event-Driven ProgrammingPower conservation is important in mobile devices since battery life isusually one of the top three reasons a consumer will choose a particulardevice.
Mobile software must be designed to be frugal in its use ofhardware components that consume power, such as the CPU, displayand radio units. These power-sink hardware components usually havevarious modes of operation including low-power modes which can beused to minimize power drain whenever the hardware components, orsoftware services related to them, are not in use.
An example of a powersink component and a related service might be a Bluetooth radio unit anda Bluetooth device discovery service. Such hardware components areoften encapsulated as shared resources in Symbian OS and are managedon behalf of the programs that use them (often using a reference countingmechanism).One power-sink hardware component that all programs utilize is theCPU.