25
votes

I have a windows service application. And debugging it by running in console mode.

Here http://support.microsoft.com/kb/842793 it is written that Timers.Timer has a bug and not firing in windows services. And workaround is to use Threading.Timer And this article is for .NET 1.0 and 1.1

I am using .NET 4 but after some time Threading.Timer also doesn't fire. So what can be the reason for this? And what can you suggest as a workaround?

Thanks,

Best Regards

EDIT: I changed timer from Threading.Timer to Timers.Timer and it is working without any problem.

5
I think a good way to speed up solution of this problem is to post Timer initialization and starting code.Vokinneberg
I am calling a function from native win32 dll, but it is on other threadAFgone

5 Answers

60
votes

Are you keeping a reference to your timer somewhere to prevent it being garbage collected?

From the docs:

As long as you are using a Timer, you must keep a reference to it. As with any managed object, a Timer is subject to garbage collection when there are no references to it. The fact that a Timer is still active does not prevent it from being collected.

14
votes

Your timer object goes out of scope and gets erased by Garbage Collector after some time, which stops callbacks from firing.

Save reference to it in a member of class.

6
votes

Work around?

Personally, I suggest using a RegisterWaitForSingleObject function as opposed to timers for the exact reason you are running into. The RegisterWaitForSingleObject registers a delegate to be called on interval that you set analgous to a timer and are super easy to implement. You could have a test harness up and running in a matter of hours. I use this method of interval firing in my Windows Services and it is a tried and true stable solution that works for me.

Read the link below and goto the links within the article for code samples and walkthroughs.

Running a Periodic Process in .NET using a Windows Service:
http://allen-conway-dotnet.blogspot.com/2009/12/running-periodic-process-in-net-using.html

2
votes

Here is how you can use RegisterWaitForSingleObject:

When you have code registering a timer like that:

const int scheduledPeriodMilliseconds = 20000;
new Timer(ServiceBusTimerCallback, parameters, 0, scheduledPeriodMilliseconds);

private static void ServiceBusTimerCallback(object params)
{
}

You can have this:

const int scheduledPeriodMilliseconds = 20000;
var allTasksWaitHandle = new AutoResetEvent(true);

ThreadPool.RegisterWaitForSingleObject(
    allTasksWaitHandle,
    (s, b) => { ServiceBusTimerCallback(parameters); },
    null,
    scheduledPeriodMilliseconds,
    false);

You can use allTasksWaitHandle.Set() after ServiceBusTimerCallback to inform user that task was done, so it will run task again immediately. This code posted above will run task after timeont will pass, so every 20 seconds.

I implemented it in WebAPI project and it works great.

0
votes

Complete example of a windows service using enterprise library for logging and recurrent threads. Remove logger.write lines if not using entreprise library

namespace Example.Name.Space
{
public partial class SmsServices : ServiceBase
{
    private static String _state = "";        
    private ManualResetEvent _stop = new ManualResetEvent(false);
    private static RegisteredWaitHandle _registeredWait;
    public WindowsServices()
    {
        InitializeComponent();
    }

    protected override void OnStart(string[] args)
    {                        
        Logger.Write("Starting service", LoggerCategory.Information);            
        _stop.Reset();
        _registeredWait = ThreadPool.RegisterWaitForSingleObject(_stop,
            PeriodicProcess, null, 5000, false);

    }

    protected override void OnStop()
    {            
       // UpdateTimer.Stop();
        _stop.Set();
        Logger.Write("Stopping service", LoggerCategory.Information);
    }        
    private static void PeriodicProcess(object state, bool timedOut)
    {

        if (timedOut)
        {
            // Periodic processing here
            Logger.Write("Asserting thread state", LoggerCategory.Debug);
            lock (_state)
            {
                if (_state.Equals("RUNNING"))
                {
                    Logger.Write("Thread already running", LoggerCategory.Debug);
                    return;
                }
                Logger.Write("Starting thread", LoggerCategory.Debug);
                _state = "RUNNING";
            }
            Logger.Write("Processing all messages", LoggerCategory.Information);
            //Do something 
            lock (_state)
            {
                Logger.Write("Stopping thread", LoggerCategory.Debug);
                _state = "STOPPED";
            }
        }
        else
            // Stop any more events coming along
            _registeredWait.Unregister(null);


    }
    }
}