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
}
}