Ejemplo n.º 1
0
        /// <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);
                }
            }
        }
Ejemplo n.º 2
0
        /// <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);
        }
Ejemplo n.º 3
0
        /// <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);
        }
Ejemplo n.º 4
0
        /// <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);
        }
Ejemplo n.º 5
0
        /// <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
                }
            }
        }