I am maintaining some code which looks something like this. It\'s a Windows service which does some work every 30 minutes. The ActualWorkDoneHere method takes about 30 sec
Here's one way to do it. Add the following variables to your class:
private readonly object syncObject = new object();
private bool stopping;
private bool stopped = true;
Then in OnStart, you do something like this (I have a helper method which does some logging in this example, and the "Run" method does the actual work).:
public override void OnStart()
{
while (stopping)
{
Thread.Sleep(MSECS_SLEEP_FOR_STOP);
}
lock (syncObject)
{
// make sure task isn't already started
if (!stopped)
{
Helper.WriteToLog(logger, Level.INFO,
string.Format("{0} {1}", TASK_NAME, "is already started."));
return;
}
stopped = false;
}
// start task in new thread
Thread thread = new Thread(Run);
thread.Start();
Helper.WriteToLog(logger, Level.INFO,
string.Format("{0} {1}", TASK_NAME, "was started."));
}
Your "Run" method, which does the work of the thread, would look like this (processInterval would be how long you want to wait between runs, you could set it in the constructor or just hardcode it):
private void Run()
{
try
{
while (!stopping)
{
// do work here
// wait for process interval
DateTime waitStart = DateTime.Now;
while (((DateTime.Now - waitStart).TotalMilliseconds < processInterval) && !stopping)
{
// give processing time to other threads
Thread.Sleep(MSECS_SLEEP_FOR_CHECK);
}
}
lock (syncObject)
{
stopped = true;
stopping = false;
}
Helper.WriteToLog(logger, Level.INFO,
string.Format("{0} {1}", TASK_NAME, "was stopped."));
}
catch (Exception e)
{
// log the exception, but ignore it (i.e. don't throw it)
Helper.LogException(logger, MethodBase.GetCurrentMethod(), e);
}
}
Then in OnStop, you would do this:
public override void OnStop()
{
lock (syncObject)
{
if (stopping || stopped)
{
Helper.WriteToLog(logger, Level.INFO,
string.Format("{0} {1}", TASK_NAME, "is already stopped."));
return;
}
stopping = true;
}
}
When I have something like this, I usually use a ManualResetEvent. This is set in the Stop() call. Then I wait with a timeout:
for (;;)
{
if (_stop.WaitOne(timeout))
break;
DoSomething();
}