예제 #1
0
 public void CreateCustomIntContext()
 {
     _customInt32      = new LockFreeInt32(0);
     _customIntBarrier = new ManualResetEvent(false);
     _customIntThreads = new List <Thread>();
     PrepareThreads(NumThreads, _customIntBarrier, WithCustomInt_Entry, _customIntThreads);
 }
예제 #2
0
 public void CreateInlinedContext()
 {
     _inlined        = new LockFreeInt32(0);
     _inlinedBarrier = new ManualResetEvent(false);
     _inlinedThreads = new List <Thread>();
     PrepareThreads(NumThreads, _inlinedBarrier, WithInlined_Entry, _inlinedThreads);
 }
예제 #3
0
        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);
        }
예제 #4
0
        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;
        }
예제 #6
0
 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);
 }
예제 #7
0
 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));
 }
예제 #9
0
        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;
        }
예제 #10
0
        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);
        }
예제 #11
0
        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
                );
        }
예제 #12
0
        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;
        }
예제 #14
0
        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);
        }
예제 #15
0
        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;
        }
예제 #17
0
        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);
                    }
                }
            }
                );
        }