public LockContext(int capacity) { _capacity = NumericHelper.PopulationCount(capacity) == 1 ? capacity : NumericHelper.NextPowerOf2(capacity); _slots = new NeedleBucket <LockSlot <T>, LazyNeedle <LockSlot <T> > > ( index => new LockSlot <T> ( this, index, _version.AdvanceNewToken() ), _capacity ); _closedSlots = new FixedSizeQueue <LockSlot <T> >(_capacity); }
public void TransactionalDataStructure() { var info = new CircularBucket <string>(32); var bucket = new NeedleBucket <int, Transact.Needle <int> >(index => index, value => new Transact.Needle <int>(value), 5); var didA = false; bool didB; using (var enteredWorkA = new ManualResetEvent(false)) { using (var enteredWorkB = new ManualResetEvent(false)) { using (var done = new ManualResetEvent(false)) { ManualResetEvent[] handles = { enteredWorkA, enteredWorkB, done }; ThreadPool.QueueUserWorkItem ( _ => { info.Add("Work A - start"); using (var transact = new Transact()) { info.Add("Work A - enter"); handles[0].Set(); info.Add("Work A - reported, waiting"); handles[1].WaitOne(); info.Add("Work A - going"); // foreach will not trigger the creation of items var got = new int[5]; var set = new int[5]; for (var index = 0; index < 5; index++) { got[index] = bucket.GetNeedle(index).Value; set[index] = got[index] + 1; bucket.GetNeedle(index).Value = set[index]; } info.Add(string.Format("Work A - Got: [{0}, {1}, {2}, {3}, {4}] - Set: [{5}, {6}, {7}, {8}, {9}]", got[0], got[1], got[2], got[3], got[4], set[0], set[1], set[2], set[3], set[4])); if (!bucket.SequenceEqual(set)) { info.Add("Work A - ??"); } info.Add("Work A - before commit"); didA = transact.Commit(); info.Add("Work A - after commit: " + didA); if (didA != bucket.SequenceEqual(set)) { info.Add("Work A - ???"); } info.Add("Work A - report"); handles[2].Set(); info.Add("Work A - done"); } } ); { info.Add("Work B - start"); using (var transact = new Transact()) { info.Add("Work B - waiting A to enter"); handles[0].WaitOne(); info.Add("Work B - telling Work A to go"); handles[1].Set(); info.Add("Work B - going"); // foreach will not trigger the creation of items var got = new int[5]; var set = new int[5]; for (var index = 0; index < 5; index++) { got[index] = bucket.GetNeedle(index).Value; set[index] = got[index] * 2; bucket.GetNeedle(index).Value = set[index]; } info.Add(string.Format("Work B - Got: [{0}, {1}, {2}, {3}, {4}] - Set: [{5}, {6}, {7}, {8}, {9}]", got[0], got[1], got[2], got[3], got[4], set[0], set[1], set[2], set[3], set[4])); if (!bucket.SequenceEqual(set)) { info.Add("Work B - ??"); } info.Add("Work B - before commit"); didB = transact.Commit(); info.Add("Work B - after commit: " + didB); if (didB != bucket.SequenceEqual(set)) { info.Add("Work B - ???"); } info.Add("Work B - waiting report"); handles[2].WaitOne(); info.Add("Work B - done"); } } var result = bucket; // These are more likely in debug mode // (+1) if (result.SequenceEqual(new[] { 1, 2, 3, 4, 5 })) { Assert.IsTrue(didA); Assert.IsFalse(didB); return; } // (*2) if (result.SequenceEqual(new[] { 0, 2, 4, 6, 8 })) { Assert.IsFalse(didA); Assert.IsTrue(didB); return; } // This are more likely with optimization enabled // (+1) and then (*2) if (result.SequenceEqual(new[] { 2, 4, 6, 8, 10 })) { Assert.IsTrue(didA); Assert.IsTrue(didB); return; } // (*2) and then (+1) if (result.SequenceEqual(new[] { 1, 3, 5, 7, 9 })) { Assert.IsTrue(didA); Assert.IsTrue(didB); return; } //--- if (result.SequenceEqual(new[] { 0, 1, 2, 3, 4 })) { Assert.IsFalse(didA); Assert.IsFalse(didB); return; } var found = result.ToArray(); Trace.WriteLine(" --- REPORT --- "); foreach (var msg in info) { Trace.WriteLine(msg); } Assert.Fail("T_T - This is what was found: [{0}, {1}, {2}, {3}, {4}]", found[0], found[1], found[2], found[3], found[4]); } } } }