Timed windows service crashing due to multiple threads running
I'm working on a simple web service w开发者_Go百科hich exports data from some data store into the database.
The service runs every 20 seconds (testing interval).
Intervals are implemented through System.Timers.Timer
class.
What is happening at the moment is:
- Service starts
- Timer starts
- 20 seconds pass and service starts the export
- Export doesn't finish within next 20 seconds and another thread kicks off attempting to do the same export.
- Eventually service crashes.
I was going to wrap the export into a separate thread, but not sure whether this will fully fix the problem.
Increasing a time interval isn't an option because I'm not sure how big the future exports will be.
Any suggestions are welcome.
Thank you
Edit:
I guess what I'm after is: 1. Start timer 2. Start thread 3. Start export 4. Don't let timer to start another thread until previous one completes...
How about in Step 3, you first disable the timer, then when you are done with the export, you re-enable the timer?
I would do something like this.
public class MyServiceController
{
private Thread m_Thread = new Thread(() => { Run(); });
private ManualResetEvent m_StopSignal = new ManualResetEvent();
public void Start()
{
m_Thread.Start();
}
public void Stop()
{
m_StopSignal.Set(); // Give it chance to end on its own.
if (!m_Thread.Join(TimeSpan.FromSeconds(30))
{
// Tear everything down forcefully as an absolute last resort.
m_Thread.Abort();
}
}
private void Run()
{
while (!m_StopSignal(TimeSpan.FromSeconds(20))
{
// Put your code here.
}
}
}
This approach allocates a single dedicated thread for processing which keeps everything synchronous. Notice that it uses a WaitHandle
to throttle the intervals. It is also important to note that I have left out a lot of code that would make MyServiceController
more robust like dealing with callers who want to call Start
multiple times, making sure the worker thread ends if it does not want to stop peacefully, etc.
Sometimes you don't want to stop your timer because it might spawning multiple threads. In this case you wrap the critical parts of each thread in Monitor.TryEnter block, locking on a shared object, so that if a thread is still running when the timer fires again, the new thread falls through harmlessly.
private static object lockObject = new object();
public void DoSomething()
{
if (System.Threading.Monitor.TryEnter(lockObject))
{
try
{
// critical stuff
}
finally
{
System.Threading.Monitor.Exit(lockObject);
}
}
}
精彩评论