예제 #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)));
                }
            }
        }
예제 #2
0
        public void CounterTest()
        {
            AtomicCounter counter = AtomicCounter.NewAtomicCounter();

            Assert.AreEqual(0, counter.GetCount());
            counter.Increment();
            Assert.AreEqual(1, counter.GetCount());
            counter.Increment(9);
            Assert.AreEqual(10, counter.GetCount());
            counter.Decrement();
            Assert.AreEqual(9, counter.GetCount());
            counter.Decrement(4);
            Assert.AreEqual(5, counter.GetCount());
            Assert.AreEqual(counter.PostDecrement(), 5);
            Assert.AreEqual(4, counter.GetCount());
            Assert.AreEqual(4, counter.PostIncrement());
            Assert.AreEqual(5, counter.GetCount());

            counter = AtomicCounter.NewAtomicCounter(2006);
            Assert.AreEqual(2006, counter.SetCount(2007));
            Assert.IsTrue(counter.SetCount(2007, 2006));
            Assert.IsFalse(counter.SetCount(2000, 2008));
            Assert.AreEqual(2006.ToString(), counter.ToString());
        }
예제 #3
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);
                }
            }
        }
예제 #4
0
        /// <summary>
        /// Close the thread gate.
        /// </summary>
        /// <remarks>
        /// A thread uses this method to obtain exclusive access to the
        /// resource represented by the thread gate. Each invocation of this
        /// method must ultimately have a corresponding invocation of the
        /// Open 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 entry into the thread gate was successfully
        /// barred by the calling thread and no other threads remain in the
        /// gate.
        /// </returns>
        public virtual bool Close(long millis)
        {
            Thread thread = Thread.CurrentThread;

            if (ClosingThread == thread && Status == ThreadGateState.Closed)
            {
                // we've already closed the gate
                CloseCount = CloseCount + 1;
                return(true);
            }

            AtomicCounter atomicState = m_atomicState;
            long          enterCount  = GetThreadLocalCount(m_slotThreadEnterCount);
            long          statusReq   = EMPTY_GATE_OPEN | enterCount;
            long          statusEnd   = EMPTY_GATE_CLOSED | enterCount;
            bool          reenter     = false;
            bool          reopen      = false;

            lock (this)
            {
                try
                {
                    if (ClosingThread == thread)
                    {
                        statusReq = EMPTY_GATE_CLOSING;

                        // if we've also "entered" we need to temporarily
                        // decrement the counter so that the last thread to
                        // exit the gate will know to notify us
                        if (enterCount > 0)
                        {
                            reenter = true;
                            atomicState.Decrement(enterCount);
                        }
                    }

                    while (true)
                    {
                        if (atomicState.SetCount(statusReq, statusEnd))
                        {
                            // we've closed the gate
                            CloseCount    = CloseCount + 1;
                            ClosingThread = thread; // in case we bypassed ThreadGateState.Closing
                            reenter       = reopen = false;
                            return(true);
                        }
                        else if (ClosingThread == null)
                        {
                            // transition to Closing state
                            if (UpdateStatus(ThreadGateState.Closing) == ThreadGateState.Destroyed)
                            {
                                // oops gate was destroyed while we were waiting
                                UpdateStatus(ThreadGateState.Destroyed);
                                throw new InvalidOperationException("ThreadGate.Close: ThreadGate has been destroyed.");
                            }

                            ClosingThread = thread;
                            statusReq     = EMPTY_GATE_CLOSING;
                            reopen        = true; // reopen if we fail

                            // if we've also "entered" we need to temporarily
                            // decrement the counter so that the last thread to
                            // exit the gate will know to notify us
                            if (enterCount > 0)
                            {
                                reenter = true;
                                atomicState.Decrement(enterCount);
                            }

                            // as we've just transititioned to CLOSING we must
                            // retest the active count since exiting threads only
                            // notify if they when in the state is CLOSING, thus
                            // we can't go to DoWait without retesting
                            continue;
                        }

                        // gate is closed or closing, wait for notification
                        millis = (int)DoWait(millis);
                        if (millis == 0)
                        {
                            return(false);
                        }
                    }
                }
                finally
                {
                    // if we transititioned to closing but didn't make it to
                    // closed; re-open the gate
                    if (reenter)
                    {
                        atomicState.Increment(enterCount); // undo temporary decrement
                    }

                    if (reopen)
                    {
                        ClosingThread = null;
                        UpdateStatus(ThreadGateState.Open);
                        Monitor.PulseAll(this);
                    }
                }
            }
        }