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(); } }
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."); } }
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); } }
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); } }
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); }