public void CreateCustomIntContext() { _customInt32 = new LockFreeInt32(0); _customIntBarrier = new ManualResetEvent(false); _customIntThreads = new List <Thread>(); PrepareThreads(NumThreads, _customIntBarrier, WithCustomInt_Entry, _customIntThreads); }
public void CreateInlinedContext() { _inlined = new LockFreeInt32(0); _inlinedBarrier = new ManualResetEvent(false); _inlinedThreads = new List <Thread>(); PrepareThreads(NumThreads, _inlinedBarrier, WithInlined_Entry, _inlinedThreads); }
public void API_TryWrappedInvoke() { var atomicInt = new LockFreeInt32(); var target = new AtomicDelegate <Func <int, int> >(); Assert.AreEqual((false, default(int)), target.TryWrappedInvoke(f => f(10))); target.Set(i => atomicInt.Add(i).CurrentValue); Assert.AreEqual((true, 10), target.TryWrappedInvoke(f => f(10))); Assert.AreEqual(10, atomicInt.Value); Assert.AreEqual(true, target.TryWrappedInvoke((Action <Func <int, int> >)(f => f(10)))); Assert.AreEqual(20, atomicInt.Value); target.Set(null); Assert.AreEqual(false, target.TryWrappedInvoke((Action <Func <int, int> >)(f => f(10)))); Assert.AreEqual(20, atomicInt.Value); // Context-consuming variants atomicInt.Set(0); target.Set(null); Assert.AreEqual((false, default(int)), target.TryWrappedInvoke((f, ctx) => f(ctx), 10)); target.Set(i => atomicInt.Add(i).CurrentValue); Assert.AreEqual((true, 10), target.TryWrappedInvoke((f, ctx) => f(ctx), 10)); Assert.AreEqual(10, atomicInt.Value); Assert.AreEqual(true, target.TryWrappedInvoke((Action <Func <int, int>, int>)((f, ctx) => f(ctx)), 10)); Assert.AreEqual(20, atomicInt.Value); target.Set(null); Assert.AreEqual(false, target.TryWrappedInvoke((Action <Func <int, int>, int>)((f, ctx) => f(ctx)), 10)); Assert.AreEqual(20, atomicInt.Value); }
public void API_TryDynamicInvoke() { var atomicInt = new LockFreeInt32(); var targetA = new AtomicDelegate <Action <int> >(); Assert.AreEqual((false, (object)null), targetA.TryDynamicInvoke(10)); targetA.Set(i => atomicInt.Add(i)); Assert.AreEqual((true, (object)null), targetA.TryDynamicInvoke(300)); Assert.Throws <TargetParameterCountException>(() => targetA.TryDynamicInvoke()); Assert.Throws <ArgumentException>(() => targetA.TryDynamicInvoke("")); Assert.Throws <TargetParameterCountException>(() => targetA.TryDynamicInvoke(3, 3)); var targetB = new AtomicDelegate <Func <int, int> >(); Assert.AreEqual((false, (object)null), targetB.TryDynamicInvoke(10)); targetB.Set(i => atomicInt.Add(i).CurrentValue); var invokeRes = targetB.TryDynamicInvoke(300); Assert.AreEqual(true, invokeRes.DelegateWasInvoked); Assert.AreEqual(600, (int)invokeRes.Result); Assert.Throws <TargetParameterCountException>(() => targetB.TryDynamicInvoke()); Assert.Throws <ArgumentException>(() => targetB.TryDynamicInvoke("")); Assert.Throws <TargetParameterCountException>(() => targetB.TryDynamicInvoke(3, 3)); }
public void FastExchange() { const int NumIterations = 3_000_000; var atomicIntA = new LockFreeInt32(0); var atomicIntB = new LockFreeInt32(0); var runner = NewRunner(new DummyImmutableVal(0, 0)); // (T) runner.GlobalSetUp = (_, __) => { atomicIntA.Set(0); atomicIntB.Set(0); }; runner.AllThreadsTearDown = target => { FastAssertEqual(NumIterations, target.Value.Alpha); FastAssertEqual(NumIterations, target.Value.Bravo); }; runner.ExecuteContinuousSingleWriterCoherencyTests( target => { var newA = atomicIntA.Increment().CurrentValue; var newB = atomicIntB.Increment().CurrentValue; var newValue = new DummyImmutableVal(newA, newB); var prev = target.FastExchange(newValue); AssertAreEqual(prev.Alpha, newA - 1); AssertAreEqual(prev.Bravo, newB - 1); }, NumIterations, target => target.Value, (prev, cur) => { FastAssertTrue(prev.Alpha <= cur.Alpha); FastAssertTrue(prev.Bravo <= cur.Bravo); } ); runner.GlobalSetUp = null; runner.AllThreadsTearDown = null; }
public void CreateManualLoopContext() { _manualLoopVector2 = new Vector2(5f, 10f); _manualLoopBarrier = new ManualResetEvent(false); _manualLoopThreads = new List <Thread>(); _manualLoopRemainingThreadCount = new LockFreeInt32(NumThreads); BenchmarkUtils.PrepareThreads(NumThreads, _manualLoopBarrier, WithManualLoop_EntryA, _manualLoopThreads); BenchmarkUtils.PrepareThreads(NumThreads, _manualLoopBarrier, WithManualLoop_EntryB, _manualLoopThreads); }
public void CreateAtomicValContext() { _atomicVal = new LockFreeValue <Vector2>(new Vector2(5f, 10f)); _atomicValBarrier = new ManualResetEvent(false); _atomicValThreads = new List <Thread>(); _atomicValRemainingThreadCount = new LockFreeInt32(NumThreads); BenchmarkUtils.PrepareThreads(NumThreads, _atomicValBarrier, WithAtomicVal_EntryA, _atomicValThreads); BenchmarkUtils.PrepareThreads(NumThreads, _atomicValBarrier, WithAtomicVal_EntryB, _atomicValThreads); }
public void CreateTupleReturnsContext() { _atomicInt64 = new LockFreeInt64(0L); _atomicInt32 = new LockFreeInt32(0); _atomicRef = new LockFreeReference <User>(new User(0, "")); _atomicVal8 = new OptimisticallyLockedValue <Val8>(new Val8(0L)); _atomicVal16 = new OptimisticallyLockedValue <Val16>(new Val16(0L)); _atomicVal32 = new OptimisticallyLockedValue <Val32>(new Val32(0L)); _atomicVal64 = new OptimisticallyLockedValue <Val64>(new Val64(0L)); }
public void ExchangeTyped() { const int NumIterations = 300_000; var initialValue = (long *)0x12345678; var runner = new ConcurrentTestCaseRunner <AtomicPtr <long> >(() => new AtomicPtr <long>(initialValue)); var atomicInt = new LockFreeInt32(0); // (T) runner.GlobalSetUp = (_, __) => { atomicInt.Set(0); }; runner.AllThreadsTearDown = target => { FastAssertEqual(initialValue + NumIterations, target.Value); }; runner.ExecuteContinuousSingleWriterCoherencyTests( target => { var newInt = atomicInt.Increment().CurrentValue; var newValue = initialValue + newInt; var prev = target.Exchange(newValue).PreviousValue; FastAssertEqual(prev, newValue - 1); }, NumIterations, target => (IntPtr)target.Value, (prev, cur) => { FastAssertTrue(prev.ToInt64() <= cur.ToInt64()); } ); runner.GlobalSetUp = null; runner.AllThreadsTearDown = null; // (Func<T, T>) runner.AllThreadsTearDown = target => { FastAssertEqual(initialValue + NumIterations, target.Value); }; runner.ExecuteFreeThreadedTests( target => { var exchRes = target.Exchange(t => t + 1); AssertAreEqual(exchRes.PreviousValue + 1, exchRes.CurrentValue); }, NumIterations ); runner.AllThreadsTearDown = null; // (Func<T, TContext, T>) runner.AllThreadsTearDown = target => { FastAssertEqual(initialValue + NumIterations, target.Value); }; runner.ExecuteFreeThreadedTests( target => { var exchRes = target.Exchange((t, ctx) => t + ctx, 1); AssertAreEqual(exchRes.PreviousValue + 1, exchRes.CurrentValue); }, NumIterations ); runner.AllThreadsTearDown = null; }
public void ShouldInvokeGlobalSetUpBeforeEachTestCase() { var globalSetUpInvocationCount = new LockFreeInt32(0); _runner.GlobalSetUp = (_, __) => globalSetUpInvocationCount.Increment(); var testCase = CreateNewTestCase(); _runner.ExecuteCustomTestCase(testCase); _runner.ExecuteCustomTestCase(testCase); _runner.ExecuteCustomTestCase(testCase); Assert.AreEqual(3, globalSetUpInvocationCount.Value); }
public void CombineRemoveRemoveAll() { const int NumIterations = 1_000; const int NumCombinesPerIteration = 30; var runner = _atomicDelegateRunnerFactory.NewRunner(); runner.ExecuteFreeThreadedTests( target => { // Note: The closure isn't just an inefficient way of testing- I'm also using it as a way to ensure the action isn't "cached" by the C# compiler. Not sure if it can do that here, but CBA to go spec-trawling to find out var invocationCounter = new LockFreeInt32(); var action = new Action(() => invocationCounter.Increment()); AssertCount(0, action); for (var i = 0; i < NumCombinesPerIteration; ++i) { target.Combine(action); AssertCount(i + 1, action); } FastAssertTrue(target.TryInvoke()); FastAssertTrue(invocationCounter.Value >= NumCombinesPerIteration); for (var i = 0; i < NumCombinesPerIteration; ++i) { var(previousValue, CurrentValue) = target.Remove(action); FastAssertNotEqual((object)previousValue, CurrentValue); AssertCount(NumCombinesPerIteration - (i + 1), action); } // Note: I'm 99% sure testing that invocationCounter doesn't change when calling target.TryInvoke() here would be a race condition. // Although I was tempted (and it seems to pass), my reasoning is that another thread could easily grab a reference to the delegate ref // before we remove the last action from the invocation list; then execute it while we're testing our invariant for (var i = 0; i < NumCombinesPerIteration; ++i) { target.Combine(action); AssertCount(i + 1, action); } invocationCounter.Value = 0; FastAssertTrue(target.TryInvoke()); FastAssertTrue(invocationCounter.Value >= NumCombinesPerIteration); target.RemoveAll(action); AssertCount(0, action); void AssertCount(int count, Action a) { var num = target.Value?.GetInvocationList()?.Count(d => ReferenceEquals(d, a)) ?? 0; FastAssertEqual(count, num); } }, NumIterations ); }
public void GetAndSet() { const int NumIterations = 3; var runner = _runnerFactory.NewRunner(false); var atomicInt = new LockFreeInt32(0); runner.GlobalSetUp = (_, __) => atomicInt.Set(0); runner.AllThreadsTearDown = target => Assert.True(target.Value); runner.ExecuteFreeThreadedTests( target => { var iterationNumber = atomicInt.Increment().CurrentValue; Assert.False(target.Get()); target.Set(iterationNumber == NumIterations); }, NumIterations ); }
public void Exchange() { const int NumIterations = 300_000; var atomicIntA = new LockFreeInt32(0); var atomicIntB = new LockFreeInt32(0); var runner = NewRunner(new DummyImmutableVal(0, 0)); // (T) runner.GlobalSetUp = (_, __) => { atomicIntA.Set(0); atomicIntB.Set(0); }; runner.AllThreadsTearDown = target => { FastAssertEqual(NumIterations, target.Value.Alpha); FastAssertEqual(NumIterations, target.Value.Bravo); }; runner.ExecuteContinuousSingleWriterCoherencyTests( target => { var newA = atomicIntA.Increment().CurrentValue; var newB = atomicIntB.Increment().CurrentValue; var newValue = new DummyImmutableVal(newA, newB); var prev = target.Exchange(newValue).PreviousValue; AssertAreEqual(prev.Alpha, newA - 1); AssertAreEqual(prev.Bravo, newB - 1); }, NumIterations, target => target.Value, (prev, cur) => { FastAssertTrue(prev.Alpha <= cur.Alpha); FastAssertTrue(prev.Bravo <= cur.Bravo); } ); runner.GlobalSetUp = null; runner.AllThreadsTearDown = null; // (Func<T, T>) runner.AllThreadsTearDown = target => { FastAssertEqual(NumIterations, target.Value.Alpha); FastAssertEqual(NumIterations, target.Value.Bravo); }; runner.ExecuteFreeThreadedTests( target => { var exchRes = target.Exchange(t => new DummyImmutableVal(t.Alpha + 1, t.Bravo + 1)); AssertAreEqual(exchRes.PreviousValue.Alpha + 1, exchRes.CurrentValue.Alpha); AssertAreEqual(exchRes.PreviousValue.Bravo + 1, exchRes.CurrentValue.Bravo); }, NumIterations ); runner.AllThreadsTearDown = null; // (Func<T, TContext, T>) runner.AllThreadsTearDown = target => { FastAssertEqual(NumIterations, target.Value.Alpha); FastAssertEqual(NumIterations * 2, target.Value.Bravo); }; runner.ExecuteFreeThreadedTests( target => { var exchRes = target.Exchange((t, ctx) => new DummyImmutableVal(t.Alpha + 1, t.Bravo + ctx), 2); AssertAreEqual(exchRes.PreviousValue.Alpha + 1, exchRes.CurrentValue.Alpha); AssertAreEqual(exchRes.PreviousValue.Bravo + 2, exchRes.CurrentValue.Bravo); }, NumIterations ); runner.AllThreadsTearDown = null; }
public void API_CombineRemoveRemoveAll() { var lastRecordedInput = new LockFreeReference <string>(); Func <string, string> initialValue = s => { lastRecordedInput.Set(s); return(s.ToUpper()); }; var target = new AtomicDelegate <Func <string, string> >(initialValue); var combineRes = target.Combine(s => s.ToLower()); Assert.AreEqual(initialValue, combineRes.PreviousValue); Assert.AreEqual("TEST", combineRes.PreviousValue("Test")); Assert.AreEqual("test", combineRes.CurrentValue("Test")); Assert.AreEqual("Test", lastRecordedInput.Value); target.TryInvoke("Input"); Assert.AreEqual("Input", lastRecordedInput.Value); combineRes = target.Combine(s => s + s); Assert.AreEqual("abcabc", target.Value("abc")); Assert.AreEqual("abc", lastRecordedInput.Value); Assert.AreEqual(combineRes.CurrentValue, target.Value); var removeRes = target.Remove(initialValue); Assert.AreEqual("qwertyqwerty", removeRes.PreviousValue("qwerty")); Assert.AreEqual("qwerty", lastRecordedInput.Value); Assert.AreEqual("ijklijkl", removeRes.CurrentValue("ijkl")); Assert.AreEqual("qwerty", lastRecordedInput.Value); Assert.AreEqual(removeRes.CurrentValue, target.Value); removeRes = target.Remove(c => "this delegate was never added"); Assert.AreEqual(removeRes.CurrentValue, removeRes.PreviousValue); Assert.AreEqual(target.Value, removeRes.PreviousValue); var invocationCounter = new LockFreeInt32(); Func <string, string> CurrentValue = s => { invocationCounter.Increment(); return(s[0].ToString()); }; target.Combine(CurrentValue); target.Combine(CurrentValue); target.Combine(CurrentValue); Assert.AreEqual((true, "r"), target.TryInvoke("rrrrr")); Assert.AreEqual(3, invocationCounter.Value); target.Remove(CurrentValue); Assert.AreEqual((true, "r"), target.TryInvoke("rrrrr")); Assert.AreEqual(5, invocationCounter.Value); removeRes = target.RemoveAll(CurrentValue); Assert.AreEqual((true, "rrrrrrrrrr"), target.TryInvoke("rrrrr")); Assert.AreEqual(5, invocationCounter.Value); Assert.AreEqual("rrrrrrrrrr", removeRes.CurrentValue("rrrrr")); Assert.AreEqual("r", removeRes.PreviousValue("rrrrr")); removeRes = target.RemoveAll(CurrentValue); Assert.AreEqual((true, "rrrrrrrrrr"), target.TryInvoke("rrrrr")); Assert.AreEqual(7, invocationCounter.Value); Assert.AreEqual("rrrrrrrrrr", removeRes.CurrentValue("rrrrr")); Assert.AreEqual(removeRes.CurrentValue, removeRes.PreviousValue); }
public void API_TryInvoke() { // Someone smarter than me could automate this with a for loop and dynamic code gen. But all those smart people are off building things that are actually useful, so here we are. // If you're reading this and want to take a crack at it though... var actionTarget = new LockFreeInt32(); Assert.AreEqual(false, new AtomicDelegate <Action>().TryInvoke()); Assert.AreEqual(true, new AtomicDelegate <Action>(() => actionTarget.Set(3)).TryInvoke()); Assert.AreEqual(3, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int> >().TryInvoke(1)); Assert.AreEqual(true, new AtomicDelegate <Action <int> >(n1 => actionTarget.Set(n1)).TryInvoke(1)); Assert.AreEqual(1, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int> >().TryInvoke(1, 2)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int> >((n1, n2) => actionTarget.Set(n1 + n2)).TryInvoke(1, 2)); Assert.AreEqual(3, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int> >().TryInvoke(1, 2, 3)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int> >((n1, n2, n3) => actionTarget.Set(n1 + n2 + n3)).TryInvoke(1, 2, 3)); Assert.AreEqual(6, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int> >().TryInvoke(1, 2, 3, 4)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int> >((n1, n2, n3, n4) => actionTarget.Set(n1 + n2 + n3 + n4)).TryInvoke(1, 2, 3, 4)); Assert.AreEqual(10, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int> >((n1, n2, n3, n4, n5) => actionTarget.Set(n1 + n2 + n3 + n4 + n5)).TryInvoke(1, 2, 3, 4, 5)); Assert.AreEqual(15, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6)).TryInvoke(1, 2, 3, 4, 5, 6)); Assert.AreEqual(21, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7)).TryInvoke(1, 2, 3, 4, 5, 6, 7)); Assert.AreEqual(28, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8)).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8)); Assert.AreEqual(36, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9)).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9)); Assert.AreEqual(45, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10)).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); Assert.AreEqual(55, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11)).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); Assert.AreEqual(66, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12)).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); Assert.AreEqual(78, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12 + n13)).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)); Assert.AreEqual(91, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12 + n13 + n14)).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)); Assert.AreEqual(105, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12 + n13 + n14 + n15)).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); Assert.AreEqual(120, actionTarget.Value); Assert.AreEqual(false, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); Assert.AreEqual(true, new AtomicDelegate <Action <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16) => actionTarget.Set(n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12 + n13 + n14 + n15 + n16)).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); Assert.AreEqual(136, actionTarget.Value); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int> >().TryInvoke()); Assert.AreEqual((true, 0), new AtomicDelegate <Func <int> >(() => 0).TryInvoke()); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int> >().TryInvoke(1)); Assert.AreEqual((true, 1), new AtomicDelegate <Func <int, int> >(n1 => n1).TryInvoke(1)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int> >().TryInvoke(1, 2)); Assert.AreEqual((true, 3), new AtomicDelegate <Func <int, int, int> >((n1, n2) => n1 + n2).TryInvoke(1, 2)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int> >().TryInvoke(1, 2, 3)); Assert.AreEqual((true, 6), new AtomicDelegate <Func <int, int, int, int> >((n1, n2, n3) => n1 + n2 + n3).TryInvoke(1, 2, 3)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int> >().TryInvoke(1, 2, 3, 4)); Assert.AreEqual((true, 10), new AtomicDelegate <Func <int, int, int, int, int> >((n1, n2, n3, n4) => n1 + n2 + n3 + n4).TryInvoke(1, 2, 3, 4)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5)); Assert.AreEqual((true, 15), new AtomicDelegate <Func <int, int, int, int, int, int> >((n1, n2, n3, n4, n5) => n1 + n2 + n3 + n4 + n5).TryInvoke(1, 2, 3, 4, 5)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6)); Assert.AreEqual((true, 21), new AtomicDelegate <Func <int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6) => n1 + n2 + n3 + n4 + n5 + n6).TryInvoke(1, 2, 3, 4, 5, 6)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7)); Assert.AreEqual((true, 28), new AtomicDelegate <Func <int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7) => n1 + n2 + n3 + n4 + n5 + n6 + n7).TryInvoke(1, 2, 3, 4, 5, 6, 7)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8)); Assert.AreEqual((true, 36), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8) => n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9)); Assert.AreEqual((true, 45), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9) => n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); Assert.AreEqual((true, 55), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10) => n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); Assert.AreEqual((true, 66), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11) => n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); Assert.AreEqual((true, 78), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12) => n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)); Assert.AreEqual((true, 91), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13) => n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12 + n13).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)); Assert.AreEqual((true, 105), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14) => n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12 + n13 + n14).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); Assert.AreEqual((true, 120), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15) => n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12 + n13 + n14 + n15).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15)); Assert.AreEqual((false, default(int)), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >().TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); Assert.AreEqual((true, 136), new AtomicDelegate <Func <int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int, int> >((n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12, n13, n14, n15, n16) => n1 + n2 + n3 + n4 + n5 + n6 + n7 + n8 + n9 + n10 + n11 + n12 + n13 + n14 + n15 + n16).TryInvoke(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16)); }
public void Assert_Coherency_Set() { const int NumIterations = 1_000_000; var atomicIntA = new LockFreeInt32(0); var atomicIntB = new LockFreeInt32(0); // void Set(T newValue, out T previousValue); var runner = NewRunner(new DummyImmutableVal(0, 0)); runner.GlobalSetUp = (_, __) => { atomicIntA.Set(0); atomicIntB.Set(0); }; runner.AllThreadsTearDown = target => { FastAssertEqual(NumIterations, target.Value.Alpha); FastAssertEqual(NumIterations, target.Value.Bravo); }; runner.ExecuteContinuousSingleWriterCoherencyTests( target => { target.Set( new DummyImmutableVal(atomicIntA.IncrementAndGet(), atomicIntB.DecrementAndGet()), out var prevValue ); FastAssertEqual(atomicIntA.Value - 1, prevValue.Alpha); FastAssertEqual(atomicIntB.Value + 1, prevValue.Bravo); }, NumIterations, target => target.Value, (prev, cur) => { FastAssertTrue(prev.Alpha <= cur.Alpha); FastAssertTrue(prev.Bravo >= cur.Alpha); } ); runner.GlobalSetUp = null; runner.AllThreadsTearDown = null; // T Set(Func<T, T> valueMapFunc); runner.AllThreadsTearDown = target => { FastAssertEqual(NumIterations, target.Value.Alpha); FastAssertEqual(-NumIterations, target.Value.Bravo); }; runner.ExecuteFreeThreadedTests( target => { var curVal = target.Value; var newVal = target.Set(t => new DummyImmutableVal(t.Alpha + 1, t.Bravo - 1)); FastAssertTrue(curVal.Alpha < newVal.Alpha); FastAssertTrue(curVal.Bravo > newVal.Bravo); }, NumIterations ); runner.AllThreadsTearDown = null; // T Set(Func<T, T> valueMapFunc, out T previousValue); runner.AllThreadsTearDown = target => { FastAssertEqual(NumIterations, target.Value.Alpha); FastAssertEqual(-NumIterations, target.Value.Bravo); }; runner.ExecuteFreeThreadedTests( target => { var curVal = target.Value; var newVal = target.Set(t => new DummyImmutableVal(t.Alpha + 1, t.Bravo - 1), out var prevVal); FastAssertTrue(curVal.Alpha < newVal.Alpha); FastAssertTrue(curVal.Bravo > newVal.Bravo); FastAssertEqual(newVal.Alpha - 1, prevVal.Alpha); FastAssertEqual(newVal.Bravo + 1, prevVal.Bravo); }, NumIterations ); runner.AllThreadsTearDown = null; }
public void TryInvokeTryWrappedInvokeTryDynamicInvoke() { const int NumIterations = 40_000; const int NumCombinesPerIteration = 3; const int ActionInputValue = 3; var runner = new ConcurrentTestCaseRunner <AtomicDelegate <Func <int, int> > >(() => new AtomicDelegate <Func <int, int> >()); var counter = new LockFreeInt32(); var writerCount = new LockFreeInt32(); var action = new Func <int, int>(n => counter.Add(n).CurrentValue); CancellationTokenSource cts = null; runner.GlobalSetUp = (_, threadConfig) => { writerCount.Value = threadConfig.WriterThreadCount; cts = new CancellationTokenSource(); }; runner.ExecuteSingleReaderTests( writerFunction: target => { for (var j = 0; j < NumIterations; j++) { for (var i = 0; i < NumCombinesPerIteration; i++) { target.Combine(action); } for (var i = 0; i < NumCombinesPerIteration; i++) { target.Remove(action); } } cts.Cancel(); }, readerFunction: target => { var numWriters = writerCount.Value; while (!cts.IsCancellationRequested) { TestTryInvoke(); TestWrappedInvoke(); TestDynamicInvoke(); void TestTryInvoke() { var curCounterValue = counter.Value; var result = target.TryInvoke(ActionInputValue); if (result.DelegateWasInvoked) { TestResult(curCounterValue, result.Result); } else { FastAssertEqual(curCounterValue, counter.Value); } } void TestWrappedInvoke() { var curCounterValue = counter.Value; var result = target.TryWrappedInvoke(t => t(ActionInputValue)); if (result.DelegateWasInvoked) { TestResult(curCounterValue, result.Result); } else { FastAssertEqual(curCounterValue, counter.Value); } curCounterValue = counter.Value; result = target.TryWrappedInvoke((t, ctx) => t(ctx), ActionInputValue); if (result.DelegateWasInvoked) { TestResult(curCounterValue, result.Result); } else { FastAssertEqual(curCounterValue, counter.Value); } curCounterValue = counter.Value; var wasInvoked = target.TryWrappedInvoke(t => { t(ActionInputValue); }); if (wasInvoked) { TestResult(curCounterValue, counter.Value); } else { FastAssertEqual(curCounterValue, counter.Value); } curCounterValue = counter.Value; wasInvoked = target.TryWrappedInvoke((t, ctx) => { t(ctx); }, ActionInputValue); if (wasInvoked) { TestResult(curCounterValue, counter.Value); } else { FastAssertEqual(curCounterValue, counter.Value); } } void TestDynamicInvoke() { var curCounterValue = counter.Value; var result = target.TryDynamicInvoke(ActionInputValue); if (result.DelegateWasInvoked) { TestResult(curCounterValue, (int)result.Result); } else { FastAssertEqual(curCounterValue, counter.Value); } } void TestResult(int previousCounterValue, int invocationResult) { var diff = invocationResult - previousCounterValue; FastAssertTrue(diff >= 0 && diff <= NumCombinesPerIteration * numWriters * ActionInputValue); FastAssertTrue(invocationResult % ActionInputValue == 0); } } } ); }