Ejemplo n.º 1
0
        /// <summary>
        /// Update the current thread gate status, without changing the
        /// active count.
        /// </summary>
        /// <remarks>
        /// The caller must hold synchronization on the ThreadGate.
        /// </remarks>
        /// <param name="status">
        /// The new status.
        /// </param>
        /// <returns>
        /// The old status.
        /// </returns>
        protected virtual ThreadGateState UpdateStatus(ThreadGateState status)
        {
            AtomicCounter atomicState     = m_atomicState;
            long          offsettedStatus = ((long)status) << STATUS_OFFSET;

            while (true)
            {
                long current  = atomicState.GetCount();
                long newValue = offsettedStatus | (current & ACTIVE_COUNT_MASK);
                if (atomicState.SetCount(current, newValue))
                {
                    return((ThreadGateState)(NumberUtils.URShift(current, STATUS_OFFSET)));
                }
            }
        }
Ejemplo n.º 2
0
        /// <summary>
        /// Enter the thread gate.
        /// </summary>
        /// <remarks>
        /// A thread uses this method to obtain non-exclusive access to the
        /// resource represented by the thread gate. Each invocation of this
        /// method must ultimately have a corresponding invocation of the
        /// Exit method.
        /// </remarks>
        /// <param name="millis">
        /// Maximum number of milliseconds to wait; pass -1 for forever or 0
        /// for no wait.
        /// </param>
        /// <returns>
        /// <b>true</b> iff the calling thread successfully entered the gate.
        /// </returns>
        public virtual bool Enter(long millis)
        {
            AtomicCounter atomicState = m_atomicState;

            if (IncrementThreadLocalCount(m_slotThreadEnterCount) > 1 || ClosingThread == Thread.CurrentThread)
            {
                // we were already in the gate, or are the one which has closed it
                // thus we must get in regardless of the state
                if ((atomicState.Increment() & ACTIVE_COUNT_MASK) > int.MaxValue)
                {
                    // the gate has been entered way too many times, we must
                    // have a cut-off somewhere, it is here as this could only
                    // be possible if a thread keeps reentering the gate
                    atomicState.Decrement();
                    DecrementThreadLocalCount(m_slotThreadEnterCount);
                    throw new InvalidOperationException("The ThreadGate is full.");
                }
                // no need to check m_slotThreadEnterVersion, to get here we must be up to date
                return(true);
            }

            bool isSuccess = false;

            try
            {
                while (true)
                {
                    long status = atomicState.GetCount();
                    switch ((ThreadGateState)(NumberUtils.URShift(status, STATUS_OFFSET)))
                    {
                    case ThreadGateState.Open:
                        if (atomicState.SetCount(status, status + 1))
                        {
                            // atomic set succeeded confirming that the gate
                            // remained open and that we made it in
                            long version = Version;
                            if (version > GetThreadLocalCount(m_slotThreadEnterVersion))
                            {
                                // the gate has been closed/opened since we
                                // last entered, flush to get up to date
                                Thread.MemoryBarrier();
                                SetThreadLocalCount(m_slotThreadEnterVersion, version);
                            }
                            return(isSuccess = true);
                        }
                        // we failed to atomically enter an open gate, which
                        // can happen if either the gate closed just as we entered
                        // or if another thread entered at the same time
                        break;     // retry

                    case ThreadGateState.Closing:
                    case ThreadGateState.Closed:
                        // we know that we were not already in the gate, and are
                        // not the one closing the gate; wait for it to open
                        lock (this)
                        {
                            ThreadGateState state = Status;
                            if (state == ThreadGateState.Closing || state == ThreadGateState.Closed)
                            {
                                // wait for the gate to open
                                millis = (int)DoWait(millis);
                                if (millis == 0L)
                                {
                                    return(false);
                                }
                            }
                            // version must be set from within sync since
                            // we have not yet entered the gate.
                            SetThreadLocalCount(m_slotThreadEnterVersion, Version);
                        }
                        break;     // retry

                    case ThreadGateState.Destroyed:
                        DecrementThreadLocalCount(m_slotThreadEnterCount);
                        throw new InvalidOperationException("ThreadGate.Enter: ThreadGate has been destroyed.");

                    default:
                        DecrementThreadLocalCount(m_slotThreadEnterCount);
                        throw new InvalidOperationException("ThreadGate.Enter: ThreadGate has an invalid status. " + this);
                    }
                }
            }
            finally
            {
                if (!isSuccess)
                {
                    DecrementThreadLocalCount(m_slotThreadEnterCount);
                }
            }
        }