using System; using System.Threading; namespace JD.Threading { /// /// A thread that starts on demand. /// public abstract class WakeUpThreadBase { #region Variables private State m_state = State.Stopped; private readonly ManualResetEvent m_stoppedEvent = new ManualResetEvent(true); #endregion #region Properties /// /// True if there is currenlty something to do. /// public bool IsRunning { get { return m_state.IsRunning; } } #endregion #region Methods protected void Join() { m_stoppedEvent.WaitOne(); } protected void WakeUp() { State oldState = DoAndSetState(DoNothing, State.Running); if (!oldState.IsRunning) { m_stoppedEvent.Reset(); QueueUserWorkItem(Execute); } } private void Execute(object dummy) { try { DoAndSetState(DoWork, State.Stopped); } finally { m_stoppedEvent.Set(); } } private State DoAndSetState(Action action, State newState) { State oldState; do { oldState = m_state; action(); } while (!AssignNewState(oldState, newState)); return oldState; } private static void DoNothing() { } private bool AssignNewState(State currentState, State newState) { return Interlocked.CompareExchange(ref m_state, newState, currentState) == currentState; } #endregion #region Abstract protected abstract void DoWork(); /// /// Pushes the job on the ThreadPool. /// protected virtual void QueueUserWorkItem(WaitCallback waitCallBack) { System.Threading.ThreadPool.QueueUserWorkItem(waitCallBack); } #endregion #region Nested private class State { private readonly bool m_isRunning; private State(bool isRunning) { m_isRunning = isRunning; } public bool IsRunning { get { return m_isRunning; } } public static State Running { get { // Need to return a new object since we dont want two requests to be considered equals. return new State(true); } } public static State Stopped { get { return new State(false); } } } #endregion } }