views:

46

answers:

3

Hi,

I'm working on a simple web service which 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:

  1. Service starts
  2. Timer starts
  3. 20 seconds pass and service starts the export
  4. Export doesn't finish within next 20 seconds and another thread kicks off attempting to do the same export.
  5. 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...

+3  A: 

How about in Step 3, you first disable the timer, then when you are done with the export, you re-enable the timer?

Moose
+1 To add, register a callback with your threaded work so the callback can re-enable the timer for you. This does however increase the interval by which the timer ticks to 20 seconds + execution time.
Adam
Thanks, trying this out now...
vikp
Fixed the problem. Thank you! :D
vikp
+2  A: 

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.

Brian Gideon
Going to try this out at home today, thanks!
vikp
We use something similar for several clients. It works well.
Junto
+1  A: 

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);
        }
    }
}
ebpower