4.8 Simple, Complicated, Yet Simple in the End
The implementation of SmallObject turned out to be quite simple. However, it cannot remain that simple because of multithreading issues. The unique SmallObjAllocator is shared by all instances of SmallObject. If these instances belong to different threads, we end up sharing the SmallObjAllocator between multiple threads. As discussed in the appendix, in this case we must take special measures. It seems as if we must go back to all layers' implementations, figure out the critical operations, and add locking appropriately.
However, although it's true that multithreading complicates things a bit, it's not that complicated because Loki already defines high-level object synchronization mechanisms. Following the principle that the best step toward reuse is to use, let's include Loki's Threads.h and make the following changes to SmallObject (changes are shown in bold):
template <template <class T> class ThreadingModel>
class SmallObject : public ThreadingModel<SmallObject>
{
... as before ...
};
The definitions of operator new and operator delete also undergo a bit of surgery:
template <template <class T> class ThreadingModel>
void* SmallObject<ThreadingModel>::operator new(std::size_t size)
{
Lock lock;
return MyAlloc::Instance().Allocate(size);
}
template <template <class T> class ThreadingModel>
void SmallObject<ThreadingModel>::operator delete(void* p, std::size_t size)
{
Lock lock;
MyAlloc::Instance().Deallocate(p, size);
}
That's it! We don't have to modify any of the previous layers—their functionality will be properly guarded by locking at the highest level.
Using the Singleton management and the multithreading features of Loki right inside Loki is witness to the power of reuse. Each of these two domains—global variables' lifetimes and multithreading—has its own complications. Trying to handle them all in SmallObject starting from first principles would have been overwhelmingly difficult—just try to get peace of mind for implementing FixedAllocator's intricate caching while facing the spectrum of multiple threads spuriously initializing the same object. . .
|