diff --git a/src/autowiring/CoreContext.h b/src/autowiring/CoreContext.h index 72fc2c91c..db9eb958b 100644 --- a/src/autowiring/CoreContext.h +++ b/src/autowiring/CoreContext.h @@ -584,6 +584,10 @@ class CoreContext: return memo.m_value.template as(); } + // Need the memo for the actual type at this point, if we don't hold this down then this + // entry might not get constructed. + auto& memo = FindByType(auto_id_t{}, true); + // We must make ourselves current for the remainder of this call: CurrentContextPusher pshr(shared_from_this()); std::shared_ptr retVal( @@ -607,7 +611,6 @@ class CoreContext: // we will simply eat this exception, and handle it silently by returning the type that // someone else has already attempted to construct, as per the documented behavior of // Construct. - auto& memo = FindByType(auto_id_t{}, true); retVal = memo.m_value.template as(); } diff --git a/src/autowiring/test/CoreContextTest.cpp b/src/autowiring/test/CoreContextTest.cpp index 389bc233e..1ac9a6094 100644 --- a/src/autowiring/test/CoreContextTest.cpp +++ b/src/autowiring/test/CoreContextTest.cpp @@ -636,3 +636,53 @@ TEST_F(CoreContextTest, AwaitTimed) { injector.join(); } + +namespace { + class HoldsMutexAndCount { + public: + volatile int hitCount = 0; + int initCount = 0; + int instanceCount = 0; + std::mutex lk; + }; + + class DelaysWithNwa { + public: + DelaysWithNwa(void) { + hmac->hitCount++; + std::lock_guard{ hmac->lk }; + + hmac->initCount++; + hmac->instanceCount++; + } + + virtual ~DelaysWithNwa(void) { + hmac->instanceCount--; + } + + AutoRequired hmac; + }; +} + +TEST_F(CoreContextTest, SimultaneousMultiInject) { + AutoCreateContext ctxt; + AutoRequired hmac{ ctxt }; + + std::unique_lock lk{ hmac->lk }; + std::thread a([ctxt] { ctxt->Inject(); }); + std::thread b([ctxt] { ctxt->Inject(); }); + + // Poor man's barrier + while (hmac->hitCount != 2) + std::this_thread::yield(); + lk.unlock(); + + a.join(); + b.join(); + + // Two initializations should have taken place due to the barrier + ASSERT_EQ(2, hmac->initCount); + + // Only one of those two instances should still be around + ASSERT_EQ(1, hmac->instanceCount); +}