public void Populate_ConcurrentPopulateIsCalledEveryTimeAndSeesOwnValues(bool useGetOrPopulate, int numberOfConsumers) { ManualResetEvent sem = new ManualResetEvent(false); int populationCount = 0; Populator populator = delegate(string key, out CacheOptions options) { if (populationCount == 0) { sem.Set(); Thread.Sleep(200); } populationCount += 1; Assert.AreEqual("key", key); options = CacheOptions.NoExpiration; return("value" + Thread.CurrentThread.ManagedThreadId); }; // Prepare a bunch of threads to concurrently populate the same key. // They should all see their own populated values when released // regardless of what the others are doing. Procedure proc = delegate { sem.WaitOne(); Assert.AreEqual("value" + Thread.CurrentThread.ManagedThreadId, Cache.Populate("key", populator)); }; IAsyncResult[] consumers = new IAsyncResult[numberOfConsumers]; for (int i = 0; i < numberOfConsumers; i++) { consumers[i] = proc.BeginInvoke(null, this); } // Now actually go populate it. Assert.AreEqual("value" + Thread.CurrentThread.ManagedThreadId, useGetOrPopulate ? Cache.GetOrPopulate("key", populator) : Cache.Populate("key", populator)); // Wait for the consumers to finish and ensure they did not fail. foreach (IAsyncResult consumer in consumers) { proc.EndInvoke(consumer); } // Ensure population happened the expected number of times. Assert.AreEqual(1 + numberOfConsumers, populationCount); }