public void EditWhileIteratingThreaded()
        {
            var d = new ConcurrentDictionary <string, string>();

            Assert.IsTrue(d.TryAdd("0", "1"));
            Assert.IsTrue(d.TryAdd("a", "b"));
            int[] expectedCount = { 2 };
            Assert.AreEqual(expectedCount[0], d.Count);
            string a          = null;
            var    foundCount = 0;
            var    didAdd     = 0;
            var    didRemove  = 0;
            var    found      = new CircularBucket <string>(16);

            ThreadStart remover = () =>
            {
                var removed = d.TryRemove("a", out a);
                if (Thread.VolatileRead(ref didRemove) == 0 && removed)
                {
                    expectedCount[0]--;
                }
                if (removed)
                {
                    Interlocked.CompareExchange(ref didRemove, 1, 0);
                }
            };

            ThreadStart adder = () =>
            {
                var added = d.TryAdd("c", "d");
                if (Thread.VolatileRead(ref didAdd) == 0 && added)
                {
                    expectedCount[0]++;
                }
                if (added)
                {
                    Interlocked.CompareExchange(ref didAdd, 1, 0);
                }
            };

            // MSDN says: "it does not represent a moment-in-time snapshot of the dictionary."
            // And also "The contents exposed through the enumerator may contain modifications made to the dictionary after GetEnumerator was called."
            foreach (var item in d)
            {
                found.Add(item.Key);
                foundCount++;
                var old = expectedCount[0];
                Assert.AreEqual(expectedCount[0], d.Count);
                {
                    var t = new Thread(remover);
                    t.Start();
                    t.Join();
                }
                if (foundCount == 1)
                {
                    Assert.AreNotEqual(old, expectedCount[0]);
                }
                else
                {
                    Assert.AreEqual(old, expectedCount[0]);
                }
                Assert.AreEqual(expectedCount[0], d.Count);
                old = expectedCount[0];
                {
                    var t = new Thread(adder);
                    t.Start();
                    t.Join();
                }
                if (foundCount == 1)
                {
                    Assert.AreNotEqual(old, expectedCount[0]);
                }
                else
                {
                    Assert.AreEqual(old, expectedCount[0]);
                }
                Assert.AreEqual(expectedCount[0], d.Count);
            }
            Assert.IsNull(a);
            var array = found.ToArray();

            if (!array.IsSupersetOf(new[] { "0", "c" }))
            {
                foreach (var item in array)
                {
                    Console.WriteLine(item);
                }
                Assert.Fail();
            }
            Assert.AreEqual(2, expectedCount[0]);
            Assert.AreEqual(1, didAdd);
            Assert.AreEqual(1, didRemove);
            Assert.IsTrue(foundCount - expectedCount[0] < 2, "foundCount: {0}, expectedCount:{1}", foundCount, expectedCount[0]);
            Assert.AreEqual(expectedCount[0], d.Count);
        }
        public void EditWhileIterating()
        {
            var d = new ConcurrentDictionary <string, string>();

            Assert.IsTrue(d.TryAdd("0", "1"));
            Assert.IsTrue(d.TryAdd("a", "b"));
            var expectedCount = 2;

            Assert.AreEqual(expectedCount, d.Count);
            string a          = null;
            var    foundCount = 0;
            var    didAdd     = false;
            var    didRemove  = false;
            var    found      = new CircularBucket <string>(16);

            // MSDN says: "it does not represent a moment-in-time snapshot of the dictionary."
            // And also "The contents exposed through the enumerator may contain modifications made to the dictionary after GetEnumerator was called."
            // Note: There is no guarantee the items are in insert order
            foreach (var item in d)
            {
                found.Add(item.Key);
                foundCount++;
                Assert.AreEqual(expectedCount, d.Count);
                var removed = d.TryRemove("a", out a);
                if (didRemove)
                {
                    Assert.IsFalse(removed);
                }
                else
                {
                    Assert.IsTrue(removed);
                    expectedCount--;
                }
                didRemove = didRemove | removed;
                Assert.IsTrue(didRemove);
                Assert.AreEqual(expectedCount, d.Count);
                var added = d.TryAdd("c", "d");
                if (didAdd)
                {
                    Assert.IsFalse(added);
                }
                else
                {
                    Assert.IsTrue(added);
                    expectedCount++;
                }
                didAdd = didAdd | added;
                Assert.IsTrue(didAdd);
                Assert.AreEqual(expectedCount, d.Count);
            }
            Assert.IsNull(a);
            var array = found.ToArray();

            if (!array.IsSupersetOf(new[] { "0", "c" }))
            {
                foreach (var item in array)
                {
                    Console.WriteLine(item);
                }
                Assert.Fail();
            }
            Assert.AreEqual(2, expectedCount);
            Assert.AreEqual(true, didAdd);
            Assert.AreEqual(true, didRemove);
            Assert.IsTrue(foundCount - expectedCount < 2, "foundCount: {0}, expectedCount:{1}", foundCount, expectedCount);
            Assert.AreEqual(expectedCount, d.Count);
        }