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
Implementing it yourself is the only safe option. Even if you find a way to find out if a thread is sleeping, you will still have a race condition if you try to kill it (because it potentially starts processing after you check and before you kill it).
Instead of Thread.Sleep you could e.g. sleep 500ms and check if the abort flag is still false, sleep another 500ms etc. before 30mins passes, then do the job, etc. (this would be a pragmatic approach). If you want something more elegant, you could use a ManualResetEvent with a timeout to wait for the main thread signalling that its time to abort.
while (true)
{
if (m_reset.WaitOne(1,false))
break;
// DoSomething
}
Please Try this inside onStop()
Wow everyone makes this so complicated. Use a Timer:
On races: The original post had a race in OnStop which has been fixed. As far as I know putting the service into a stopped state will not abort threadpool threads which are used to service the timer. The condition of the timer firing and the service being stopped at the same time is irrelevant. ActualWorkDoneHere() will either run, or not run. Both are acceptable conditions.
namespace WorkService
{
public partial class WorkService : ServiceBase
{
protected const int sleepMinutes = 30;
protected System.Timers.Timer _interval;
protected bool _running = false;
public WorkService()
{
InitializeComponent();
_interval = new System.Timers.Timer();
_interval.Elapsed += new ElapsedEventHandler(OnTimedEvent);
_interval.Interval = sleepMinutes * 60 * 1000;
_running = false;
}
protected override void OnStart(string[] args)
{
_running = true;
_interval.Enabled = true;
}
protected override void OnStop()
{
_interval.Enabled = false;
_running = false;
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
if(_running)
ActualWorkDoneHere();
}
}
}
You could use a lock object to prevent the thread being stopped while your work is actually happening...
private static readonly object _syncRoot = new object();
protected override void OnStop()
{
lock (_syncRoot)
{
_workerThread.Abort();
}
}
static void DoWork()
{
int sleepMinutes = 30;
while (true)
{
lock (_syncRoot)
{
ActualWorkDoneHere();
}
System.Threading.Thread.Sleep(new TimeSpan(0, sleepMinutes, 0));
}
}
You should be careful though - if your ActualWorkDoneHere()
function takes too long, windows will report the service as failing to stop.
Try using an autoreset flag to handle stopping of the service. In that case you would not have to perform thread abort. Have added the sample code below
namespace WorkService
{
public partial class WorkService : ServiceBase
{
AutoResetEvent serviceStopEvent = new AutoResetEvent( false);
public WorkService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
Thread workerThread = new Thread(new ThreadStart(DoWork));
workerThread.Start();
}
protected override void OnStop()
{
serviceStopEvent.Set();
}
static void DoWork()
{
int sleepMinutes = 30;
WaitHandle[ ] handles = new WaitHandle[ ] { serviceStopEvent };
while (WaitHandle.WaitAny( handles))
{
ActualWorkDoneHere();
}
}
}
}
Cheers, Bharath.
My service listens on a network socket so what I did is create a joined pair of network sockets and used the select system call to listen on both. If the joined pair reported ready to read I knew to shutdown the service.
This trick can be used to trigger an arbitrary number of threads to shut down so long as none of them actually read from the connected pair.