public void WithSingleValueReturns() { // 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 += _fastAtomicLong.FastIncrement(); longResultVar += _fastAtomicLong.FastDecrement(); longResultVar += _fastAtomicLong.FastExchange(i); intResultVar += _fastAtomicInt.FastIncrement(); intResultVar += _fastAtomicInt.FastDecrement(); intResultVar += _fastAtomicInt.FastTryExchange(i, i - 1) == i - 1 ? 1 : 0; var newUser = new User(i, "Xenoprimate"); refResultVar = _fastAtomicRef.FastExchange(newUser).Name; refResultVar = _fastAtomicRef.FastTryExchange(new User(i * 2, "Ben"), newUser).LoginID == newUser.LoginID ? refResultVar : String.Empty; valResultVar += _fastAtomicVal8.FastExchange(new Val8(i)).A; valResultVar += _fastAtomicVal16.FastTryExchange(new Val16(i + 1), new Val16(i)).A == i ? 0 : 1; valResultVar += _fastAtomicVal32.FastExchange(new Val32(i)).A; valResultVar += _fastAtomicVal64.FastTryExchange(new Val64(i + 1), new Val64(i)).A == i ? 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."); } }
public void EquatableFastTryExchange() { const int NumIterations = 100_000; var runner = _equatableRefRunnerFactory.NewRunner(new DummyEquatableRef(0L)); // Test: Return value of method is always consistent runner.ExecuteFreeThreadedTests( atomicRef => { var curValue = atomicRef.Value; var newValue = new DummyEquatableRef(curValue.LongProp + 1L); var prevValue = atomicRef.FastTryExchange(newValue, curValue); var wasSet = prevValue.Equals(curValue); var setValue = wasSet ? newValue : prevValue; if (wasSet) { Assert.AreEqual(curValue, prevValue); Assert.AreEqual(newValue, setValue); } else { Assert.AreNotEqual(curValue, prevValue); Assert.AreEqual(setValue, prevValue); } }, NumIterations ); // Test: Method does what is expected and is safe from race conditions runner.AllThreadsTearDown = atomicRef => Assert.AreEqual(NumIterations, atomicRef.Value.LongProp); runner.ExecuteFreeThreadedTests( atomicRef => { while (true) { var curValue = atomicRef.Value; if (curValue.LongProp == NumIterations) { return; } var newValue = new DummyEquatableRef(curValue.LongProp + 1L); var prevValue = atomicRef.FastTryExchange(newValue, curValue); var wasSet = prevValue.Equals(curValue); var setValue = wasSet ? newValue : prevValue; if (wasSet) { Assert.AreEqual(curValue, prevValue); Assert.AreEqual(newValue, setValue); } else { Assert.AreNotEqual(curValue, prevValue); Assert.AreEqual(setValue, prevValue); } } } ); runner.AllThreadsTearDown = null; // Test: Method always exhibits coherency for consecutive reads from external threads runner.ExecuteContinuousCoherencyTests( atomicRef => { var curValue = atomicRef.Value; var newValue = new DummyEquatableRef(curValue.LongProp + 1L); atomicRef.FastTryExchange(newValue, 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); atomicImmutable.FastTryExchange(new DummyImmutableRef(), dummyImmutableB); Assert.AreEqual(dummyImmutableA, atomicImmutable.Value); atomicEquatable.Set(dummyEquatableA); var newVal = new DummyEquatableRef(); atomicEquatable.FastTryExchange(newVal, dummyEquatableB); Assert.AreEqual(newVal, atomicEquatable.Value); }