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; }