WIP: draft internal structure of dependency factory

This commit is contained in:
Fischlurch 2013-10-16 04:46:20 +02:00
parent 567ab3819b
commit f93c7f8930
2 changed files with 58 additions and 44 deletions

View file

@ -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

View file

@ -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();
}