/// <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))); } } }
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()); }
/// <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); } } }