Example #1
0
        /// <summary>
        /// Shifts the gear and blocks until all operations in the old drive mode complete.
        /// If OnGearShift is not null it's launched in a new Task, wrapped in a try catch block,
        /// swallowing all potential exceptions.
        /// </summary>
        /// <param name="g">The new concurrent mode.</param>
        /// <param name="f">Guarantees the execution of f() within the lock scope, in case that other shifts are waiting.</param>
        /// <param name="timeout">In milliseconds, by default is -1, which is indefinitely.</param>
        /// <returns>The old gear.</returns>
        /// <exception cref="System.SynchronizationException">Code.SignalAwaitTimeout</exception>
        public TesseractGear Clutch(TesseractGear g, Action f = null, int timeout = -1)
        {
            // One call at a time
            lock (shiftLock)
            {
                int old = -1;

                if (Drive != g)
                {
                    // There must be no other resets anywhere
                    gearShift.Reset();

                    old = Interlocked.Exchange(ref i[DRIVE], (int)g);

                    // Wait for all concurrent operations to finish
                    if (Volatile.Read(ref i[CCOPS]) > 0)
                    {
                        if (!gearShift.WaitOne(timeout))
                        {
                            throw new SynchronizationException(SynchronizationException.Code.SignalAwaitTimeout);
                        }
                    }

                    if (OnGearShift != null)
                    {
                        Task.Run(() =>
                        {
                            try
                            {
                                OnGearShift(g);
                            }
                            catch { }
                        });
                    }
                }
                else
                {
                    old = (int)g;
                }

                // Give a chance to at least one function to be executed,
                // in case there are competing shifts.
                if (f != null)
                {
                    f();
                }

                return((TesseractGear)old);
            }
        }
Example #2
0
        /// <summary>
        /// Expands or shrinks the virtual array to the number of SIDE tiles fitting the requested length.
        /// If the AppendIndex is greater that the new length, it's cut to length -1.
        /// If shrinking and counting, the number of not-null values (ItemsCount) is also updated.
        /// The Drive must be P when shrinking.
        /// </summary>
        /// <param name="length">The new length.</param>
        /// <param name="expand">The intent of the caller.</param>
        /// <exception cref="System.ArgumentOutOfRangeException">If length is negative</exception>
        /// <exception cref="System.InvalidOperationException">
        /// If the Drive is not P when shrinking.</exception>
        public bool Resize(int length, bool expand)
        {
            Interlocked.Increment(ref i[CCOPS]);
            TesseractGear inDrive = Drive;

            try
            {
                var slots = Volatile.Read(ref i[SLOTS]);
                if (length < 0)
                {
                    throw new ArgumentOutOfRangeException("length");
                }
                if (length == slots)
                {
                    return(false);
                }

                lock (commonLock)
                {
                    var als = Volatile.Read(ref i[SLOTS]);

                    if (length == als)
                    {
                        return(false);
                    }
                    if (length > als)
                    {
                        return(expand ? alloc(length, als) > als : false);
                    }
                    else
                    {
                        if (expand)
                        {
                            return(false);
                        }

                        if (inDrive != TesseractGear.P)
                        {
                            throw new InvalidOperationException("Wrong drive");
                        }

                        var toSize = length > 0 ? length + SIDE : 0;
                        var p      = new TesseractPos(als);

                        while (als > toSize)
                        {
                            p.D2--;
                            if (p.D2 < 1)
                            {
                                blocks[p.D0][p.D1] = null;
                                p.D1--;
                                if (p.D1 < 1)
                                {
                                    p.D0--;
                                    p.D1 = SIDE - 1;
                                }
                                p.D2 = SIDE - 1;
                            }
                            else
                            {
                                blocks[p.D0][p.D1][p.D2] = null;
                            }

                            als -= SIDE;
                        }

                        Volatile.Write(ref i[SLOTS], als);

                        if (AppendIndex >= length)
                        {
                            Interlocked.Exchange(ref i[INDEX], length - 1);
                        }
                        if (CountNotNulls)
                        {
                            int notNull = 0;
                            foreach (var c in NotNullItems())
                            {
                                notNull++;
                            }
                            Interlocked.Exchange(ref i[NNCNT], notNull);
                        }

                        return(true);
                    }
                }
            }
            finally
            {
                if (Interlocked.Decrement(ref i[CCOPS]) == 0 && inDrive != Drive)
                {
                    gearShift.Set();
                }
            }
        }