public async Task GetRequiredService_ResolvingSameSingletonInTwoThreads_SameServiceReturned()
        {
            using (var mreForThread1 = new ManualResetEvent(false))
                using (var mreForThread2 = new ManualResetEvent(false))
                    using (var mreForThread3 = new ManualResetEvent(false))
                    {
                        InnerSingleton   innerSingleton = null;
                        OuterSingleton   outerSingleton = null;
                        IServiceProvider sp             = null;

                        // Arrange
                        var services = new ServiceCollection();

                        services.AddSingleton <OuterSingleton>();
                        services.AddSingleton(sp => new InnerSingleton(mreForThread1, mreForThread2));

                        sp = services.BuildServiceProvider();

                        var t1 = Task.Run(() =>
                        {
                            outerSingleton = sp.GetRequiredService <OuterSingleton>();
                        });

                        // Wait until mre2 gets set in InnerSingleton ctor
                        mreForThread2.WaitOne();

                        var t2 = Task.Run(() =>
                        {
                            mreForThread3.Set();

                            // This waits on InnerSingleton singleton lock that is taken in thread 1
                            innerSingleton = sp.GetRequiredService <InnerSingleton>();
                        });

                        mreForThread3.WaitOne();

                        // Set a timeout before unblocking execution of both thread1 and thread2 via mre1:
                        Assert.False(mreForThread1.WaitOne(10));

                        // By this time thread 1 has already reached InnerSingleton ctor and is waiting for mre1.
                        // within the GetRequiredService call, thread 2 should be waiting on a singleton lock for InnerSingleton
                        // (rather than trying to instantiating InnerSingleton twice).
                        mreForThread1.Set();

                        // Act
                        await t1;
                        await t2;

                        // Assert
                        Assert.NotNull(outerSingleton);
                        Assert.NotNull(innerSingleton);
                        Assert.Same(outerSingleton.InnerSingleton, innerSingleton);
                    }
        }
 public OuterSingleton(InnerSingleton innerSingleton)
 {
     InnerSingleton = innerSingleton;
 }