예제 #1
0
        void ExchangeUser(string context)
        {
            var spinner = new SpinWait();

            while (true)
            {
                var curValue = _manualLoopsUser.Get();
                var newValue = new User(curValue.LoginID, context);

                if (_manualLoopsUser.TryExchange(newValue, curValue).ValueWasSet)
                {
                    return;
                }
                spinner.SpinOnce();
            }
        }
예제 #2
0
        public void WithTupleReturns()
        {
            // These vars basically used to ensure the compiler doesn't optimise away the return values entirely
            var longResultVar = 0L;
            var intResultVar  = 0;
            var refResultVar  = "";
            var valResultVar  = 0L;

            for (var i = 0; i < NumIterations; ++i)
            {
                longResultVar += _atomicLong.Increment().CurrentValue;
                longResultVar += _atomicLong.Decrement().CurrentValue;
                longResultVar += _atomicLong.Exchange(i).PreviousValue;

                intResultVar += _atomicInt.Increment().CurrentValue;
                intResultVar += _atomicInt.Decrement().CurrentValue;
                intResultVar += _atomicInt.TryExchange(i, i - 1).ValueWasSet ? 1 : 0;

                var newUser = new User(i, "Xenoprimate");
                refResultVar = _atomicRef.Exchange(newUser).PreviousValue.Name;
                refResultVar = _atomicRef.TryExchange(new User(i * 2, "Ben"), newUser).ValueWasSet ? refResultVar : String.Empty;

                valResultVar += _atomicVal8.Exchange(new Val8(i)).PreviousValue.A;
                valResultVar += _atomicVal16.TryExchange(new Val16(i + 1), new Val16(i)).ValueWasSet ? 0 : 1;
                valResultVar += _atomicVal32.Exchange(new Val32(i)).PreviousValue.A;
                valResultVar += _atomicVal64.TryExchange(new Val64(i + 1), new Val64(i)).ValueWasSet ? 0 : 1;

                SimulateContention(ContentionLevel);
            }

            if (longResultVar != 1499996500003L || intResultVar != -728379967 || !refResultVar.Equals("Ben", StringComparison.Ordinal) || valResultVar != 999997000002L)
            {
                throw new ApplicationException("This will never happen; it's just here to force the compiler not to optimise away these vars. These results were measured before.");
            }
        }
예제 #3
0
        void WithClosureCapturingFuncs_Entry()
        {
            var usernameA = "aaaa";
            var usernameB = "bbbb";

            for (var i = 0; i < NumIterations; i++)
            {
                _closureCapturingFuncsUser.Exchange(u => new User(u.LoginID, (i & 1) == 0 ? usernameA : usernameB));
                _closureCapturingFuncsUser.TryExchange(u => new User(u.LoginID, (i & 1) == 0 ? usernameA : usernameB), (cur, next) => cur.Name == usernameA || next.Name == usernameA);

                _closureCapturingFuncsLong.TryBoundedExchange(l => l + i, 0L, NumIterations);
                _closureCapturingFuncsLong.TryMinimumExchange(l => l + i, 0L);
                _closureCapturingFuncsLong.TryMaximumExchange(l => l + i, NumIterations);

                BenchmarkUtils.SimulateContention(ContentionLevel);
            }
        }
예제 #4
0
        void WithContextualFuncs_Entry()
        {
            var usernameA = "aaaa";
            var usernameB = "bbbb";

            for (var i = 0; i < NumIterations; i++)
            {
                _contextualFuncsUser.Exchange((u, ctx) => new User(u.LoginID, ctx), (i & 1) == 0 ? usernameA : usernameB);
                _contextualFuncsUser.TryExchange((u, ctx) => new User(u.LoginID, ctx), (i & 1) == 0 ? usernameA : usernameB, (cur, next, ctx) => cur.Name == ctx || next.Name == ctx, usernameA);

                _contextualFuncsLong.TryBoundedExchange((l, ctx) => l + ctx, i, 0L, NumIterations);
                _contextualFuncsLong.TryMinimumExchange((l, ctx) => l + ctx, i, 0L);
                _contextualFuncsLong.TryMaximumExchange((l, ctx) => l + ctx, i, NumIterations);

                BenchmarkUtils.SimulateContention(ContentionLevel);
            }
        }
예제 #5
0
        public void EquatableMappedTryExchange()
        {
            const int NumIterations = 100_000;

            var equatableRunner = _equatableRefRunnerFactory.NewRunner(new DummyEquatableRef(0L));

            // Test: Return value of method is always consistent
            equatableRunner.ExecuteFreeThreadedTests(
                atomicRef => {
                var curValue = atomicRef.Value;
                var(wasSet, prevValue, CurrentValue) = atomicRef.TryExchange(c => new DummyEquatableRef(c.LongProp + 1L), curValue);
                if (wasSet)
                {
                    Assert.AreEqual(curValue, prevValue);
                    Assert.AreEqual(new DummyEquatableRef(prevValue.LongProp + 1L), CurrentValue);
                }
                else
                {
                    Assert.AreNotEqual(curValue, prevValue);
                }
            },
                NumIterations
                );

            // Test: Method does what is expected and is safe from race conditions
            equatableRunner.AllThreadsTearDown = atomicRef => Assert.AreEqual(NumIterations, atomicRef.Value.LongProp);
            equatableRunner.ExecuteFreeThreadedTests(
                atomicRef => {
                while (true)
                {
                    var curValue = atomicRef.Value;
                    if (curValue.LongProp == NumIterations)
                    {
                        return;
                    }
                    var(wasSet, prevValue, CurrentValue) = atomicRef.TryExchange(c => new DummyEquatableRef(c.LongProp + 1L), curValue);
                    if (wasSet)
                    {
                        Assert.AreEqual(curValue, prevValue);
                        Assert.AreEqual(new DummyEquatableRef(prevValue.LongProp + 1L), CurrentValue);
                    }
                    else
                    {
                        Assert.AreNotEqual(curValue, prevValue);
                    }
                }
            }
                );
            equatableRunner.AllThreadsTearDown = null;

            // Test: Method always exhibits coherency for consecutive reads from external threads
            equatableRunner.ExecuteContinuousCoherencyTests(
                atomicRef => {
                var curValue = atomicRef.Value;
                atomicRef.TryExchange(c => new DummyEquatableRef(c.LongProp + 1L), curValue);
            },
                NumIterations,
                atomicRef => atomicRef.Value,
                (prev, cur) => Assert.True(cur.LongProp >= prev.LongProp)
                );

            // Test: Custom equality is used for types that provide it
            var dummyImmutableA = new DummyImmutableRef("Xenoprimate Rules");
            var dummyImmutableB = new DummyImmutableRef("Xenoprimate Rules");
            var dummyEquatableA = new DummyEquatableRef("Xenoprimate Rules");
            var dummyEquatableB = new DummyEquatableRef("Xenoprimate Rules");
            var atomicImmutable = new AtomicRef <DummyImmutableRef>();
            var atomicEquatable = new AtomicRef <DummyEquatableRef>();

            atomicImmutable.Set(dummyImmutableA);
            Assert.AreEqual(false, atomicImmutable.TryExchange(c => new DummyImmutableRef(), dummyImmutableB).ValueWasSet);
            atomicEquatable.Set(dummyEquatableA);
            Assert.AreEqual(true, atomicEquatable.TryExchange(c => new DummyEquatableRef(), dummyEquatableB).ValueWasSet);
        }