WIP: draft internal structure of dependency factory
This commit is contained in:
parent
567ab3819b
commit
f93c7f8930
2 changed files with 58 additions and 44 deletions
|
|
@ -44,13 +44,15 @@ namespace lib {
|
|||
* Access point to singletons and other kinds of dependencies.
|
||||
* Actually this is a Factory object, which is typically placed into a static field
|
||||
* of the Singleton (target) class or some otherwise suitable interface.
|
||||
* @note internally uses static fields, so all factory instances share pInstance_
|
||||
* @note there is an ongoing discussion regarding Double Checked Locking pattern,
|
||||
* which in this case boils down to the question: does \c pthread_mutex_lock/unlock
|
||||
* constitute a memory barrier, such as to force any memory writes done within
|
||||
* the singleton ctor to be flushed and visible to other threads when releasing
|
||||
* the lock? To my understanding, the answer is yes. See
|
||||
* http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap04.html#tag_04_10
|
||||
* @note uses static fields internally, so all factory instances share pInstance_
|
||||
* @remark there is an ongoing discussion regarding the viability of the
|
||||
* Double Checked Locking pattern, which requires either the context of a clearly defined
|
||||
* language memory model (as in Java), or needs to be supplemented by memory barriers.
|
||||
* In our case, this debate boils down to the question: does \c pthread_mutex_lock/unlock
|
||||
* constitute a memory barrier, such as to force any memory writes happening \em within
|
||||
* the singleton ctor to be flushed and visible to other threads when releasing the lock?
|
||||
* To my understanding, the answer is yes. See
|
||||
* [posix](http://www.opengroup.org/onlinepubs/000095399/basedefs/xbd_chap04.html#tag_04_10)
|
||||
* @param SI the class of the Singleton instance
|
||||
* @param Create policy defining how to create/destroy the instance
|
||||
* @param Life policy defining how to manage Singleton Lifecycle
|
||||
|
|
@ -58,9 +60,11 @@ namespace lib {
|
|||
template<class SI>
|
||||
class Depend
|
||||
{
|
||||
typedef lib::ClassLock<SI> ThreadLock;
|
||||
typedef ClassLock<SI> ThreadLock;
|
||||
typedef DependencyFactory<SI> Factory;
|
||||
|
||||
static SI* volatile pInstance_;
|
||||
static SI* volatile instance;
|
||||
static Factory factory;
|
||||
|
||||
|
||||
public:
|
||||
|
|
@ -72,55 +76,59 @@ namespace lib {
|
|||
SI&
|
||||
operator() ()
|
||||
{
|
||||
if (!pInstance_)
|
||||
if (!instance)
|
||||
{
|
||||
ThreadLock guard;
|
||||
|
||||
if (!pInstance_)
|
||||
{
|
||||
if (isDead_)
|
||||
{
|
||||
Life<SI>::onDeadReference();
|
||||
isDead_ = false;
|
||||
}
|
||||
pInstance_ = Create<SI>::create();
|
||||
Life<SI>::scheduleDelete (&destroy);
|
||||
} }
|
||||
ENSURE (pInstance_);
|
||||
ENSURE (!isDead_);
|
||||
return *pInstance_;
|
||||
if (!instance)
|
||||
instance = factory.buildInstance();
|
||||
}
|
||||
ENSURE (instance);
|
||||
return *instance;
|
||||
}
|
||||
|
||||
private:
|
||||
/** @internal helper used to delegate destroying the single instance
|
||||
* to the Create policy, at the same time allowing the Life policy
|
||||
* to control the point in the Application lifecycle when the
|
||||
* destruction of this instance occurs.
|
||||
*/
|
||||
static void destroy()
|
||||
void
|
||||
shutdown()
|
||||
{
|
||||
REQUIRE (!isDead_);
|
||||
Create<SI>::destroy (pInstance_);
|
||||
pInstance_ = 0;
|
||||
isDead_ = true;
|
||||
ThreadLock guard;
|
||||
|
||||
factory.deconfigure (instance);
|
||||
instance = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
injectReplacement (SI* mock)
|
||||
{
|
||||
if (mock)
|
||||
{
|
||||
factory.takeOwnership (mock); // EX_SANE
|
||||
|
||||
ThreadLock guard;
|
||||
factory.shaddow (instance);
|
||||
instance = mock;
|
||||
}
|
||||
else
|
||||
{
|
||||
factory.discardMock (instance); // EX_FREE
|
||||
|
||||
ThreadLock guard;
|
||||
instance = factory.restore (); // EX_SANE
|
||||
}
|
||||
}
|
||||
|
||||
Depend ();
|
||||
Depend (typename Factory::Constructor ctor);
|
||||
|
||||
private:
|
||||
};
|
||||
|
||||
|
||||
// Storage for SingletonFactory's static fields...
|
||||
template<class SI>
|
||||
SI* volatile Depend<SI>::pInstance_;
|
||||
SI* volatile Depend<SI>::instance;
|
||||
|
||||
|
||||
|
||||
///// Question: can we get rid of the static fields?
|
||||
///// this is tricky because of invoking the destructors. If we rely on instance vars,
|
||||
///// the object may already have been released when the runtime system calls the
|
||||
///// destructors of static objects at shutdown.
|
||||
///// It seems this would either cost us much of the flexibility or get complicated
|
||||
///// to a point where we could as well implement our own Dependency Injection Manager.
|
||||
///// But the whole point of my pervasive use of this singleton template is to remain
|
||||
///// below this borderline of integration ("IoC yes, but avoid DI").
|
||||
|
||||
} // namespace lib
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -87,7 +87,13 @@ namespace test{
|
|||
virtual void
|
||||
run (Arg)
|
||||
{
|
||||
UNIMPLEMENTED ("dependency creation");
|
||||
verify_defaultSingletonCreation();
|
||||
verify_renewal();
|
||||
verify_SubclassCreation();
|
||||
verify_FactoryDefinition_is_sticky();
|
||||
verify_customFactory();
|
||||
verify_temporaryReplacement();
|
||||
verify_automaticReplacement();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue