/// <summary> /// Updates with the given value. /// </summary> /// <param name="x"> the value </param> public virtual void Accumulate(long x) { Cell[] @as; long b, v, r; int m; Cell a; if ((@as = Cells) != null || (r = Function.ApplyAsLong(b = @base, x)) != b && !CasBase(b, r)) { bool uncontended = true; if (@as == null || (m = @as.Length - 1) < 0 || (a = @as[Probe & m]) == null || !(uncontended = (r = Function.ApplyAsLong(v = a.Value, x)) == v || a.Cas(v, r))) { LongAccumulate(x, Function, uncontended); } } }
/// <summary> /// Atomically updates the current value with the results of /// applying the given function to the current and given values, /// returning the updated value. The function should be /// side-effect-free, since it may be re-applied when attempted /// updates fail due to contention among threads. The function /// is applied with the current value as its first argument, /// and the given update as the second argument. /// </summary> /// <param name="x"> the update value </param> /// <param name="accumulatorFunction"> a side-effect-free function of two arguments </param> /// <returns> the updated value /// @since 1.8 </returns> public long AccumulateAndGet(long x, LongBinaryOperator accumulatorFunction) { long prev, next; do { prev = Get(); next = accumulatorFunction.ApplyAsLong(prev, x); } while (!CompareAndSet(prev, next)); return(next); }
/// <summary> /// Atomically updates the field of the given object managed by this /// updater with the results of applying the given function to the /// current and given values, returning the previous value. The /// function should be side-effect-free, since it may be re-applied /// when attempted updates fail due to contention among threads. The /// function is applied with the current value as its first argument, /// and the given update as the second argument. /// </summary> /// <param name="obj"> An object whose field to get and set </param> /// <param name="x"> the update value </param> /// <param name="accumulatorFunction"> a side-effect-free function of two arguments </param> /// <returns> the previous value /// @since 1.8 </returns> public long GetAndAccumulate(T obj, long x, LongBinaryOperator accumulatorFunction) { long prev, next; do { prev = Get(obj); next = accumulatorFunction.ApplyAsLong(prev, x); } while (!CompareAndSet(obj, prev, next)); return(prev); }
/// <summary> /// Atomically updates the element at index {@code i} with the /// results of applying the given function to the current and /// given values, returning the updated value. The function should /// be side-effect-free, since it may be re-applied when attempted /// updates fail due to contention among threads. The function is /// applied with the current value at index {@code i} as its first /// argument, and the given update as the second argument. /// </summary> /// <param name="i"> the index </param> /// <param name="x"> the update value </param> /// <param name="accumulatorFunction"> a side-effect-free function of two arguments </param> /// <returns> the updated value /// @since 1.8 </returns> public long AccumulateAndGet(int i, long x, LongBinaryOperator accumulatorFunction) { long offset = CheckedByteOffset(i); long prev, next; do { prev = GetRaw(offset); next = accumulatorFunction.ApplyAsLong(prev, x); } while (!CompareAndSetRaw(offset, prev, next)); return(next); }
/// <summary> /// Handles cases of updates involving initialization, resizing, /// creating new Cells, and/or contention. See above for /// explanation. This method suffers the usual non-modularity /// problems of optimistic retry code, relying on rechecked sets of /// reads. /// </summary> /// <param name="x"> the value </param> /// <param name="fn"> the update function, or null for add (this convention /// avoids the need for an extra field or function in LongAdder). </param> /// <param name="wasUncontended"> false if CAS failed before call </param> internal void LongAccumulate(long x, LongBinaryOperator fn, bool wasUncontended) { int h; if ((h = Probe) == 0) { ThreadLocalRandom.Current(); // force initialization h = Probe; wasUncontended = true; } bool collide = false; // True if last slot nonempty for (;;) { Cell[] @as; Cell a; int n; long v; if ((@as = Cells) != null && (n = @as.Length) > 0) { if ((a = @as[(n - 1) & h]) == null) { if (CellsBusy == 0) // Try to attach new Cell { Cell r = new Cell(x); // Optimistically create if (CellsBusy == 0 && CasCellsBusy()) { bool created = false; try // Recheck under lock { Cell[] rs; int m, j; if ((rs = Cells) != null && (m = rs.Length) > 0 && rs[j = (m - 1) & h] == null) { rs[j] = r; created = true; } } finally { CellsBusy = 0; } if (created) { break; } continue; // Slot is now non-empty } } collide = false; } else if (!wasUncontended) // CAS already known to fail { wasUncontended = true; // Continue after rehash } else if (a.Cas(v = a.Value, ((fn == null) ? v + x : fn.ApplyAsLong(v, x)))) { break; } else if (n >= NCPU || Cells != @as) { collide = false; // At max size or stale } else if (!collide) { collide = true; } else if (CellsBusy == 0 && CasCellsBusy()) { try { if (Cells == @as) // Expand table unless stale { Cell[] rs = new Cell[n << 1]; for (int i = 0; i < n; ++i) { rs[i] = @as[i]; } Cells = rs; } } finally { CellsBusy = 0; } collide = false; continue; // Retry with expanded table } h = AdvanceProbe(h); } else if (CellsBusy == 0 && Cells == @as && CasCellsBusy()) { bool init = false; try // Initialize table { if (Cells == @as) { Cell[] rs = new Cell[2]; rs[h & 1] = new Cell(x); Cells = rs; init = true; } } finally { CellsBusy = 0; } if (init) { break; } } else if (CasBase(v = @base, ((fn == null) ? v + x : fn.ApplyAsLong(v, x)))) { break; // Fall back on using base } } }