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; }