2

I want to do some periodic work on a worker thread which signals when the work is completed. When signaled, I want to wait for 5 seconds and re-do the work. I wrote the following code:

public class WinService : ServiceBase
{
    private readonly ManualResetEvent stopPeriodicProcess = new ManualResetEvent(false);

    protected override void OnStart(string[] args)
    {
        stopPeriodicProcess.Reset();
        ThreadPool.RegisterWaitForSingleObject(stopPeriodicProcess, InitializeEngines, null,5000, true);          
    }

    public void InitializeEngines(object state, bool timedOut)
    {       
        engine.LoadSettings();

        Task.Factory.StartNew(engine.DoSomeWork); //Fire and forget     
    }

    private void WorkCompletedEventHandler(object sender, WorkCompletedEventArgs e)
    {
        ThreadPool.RegisterWaitForSingleObject(stopPeriodicProcess,
                                               (state, timedOut) => DoPeriodicProcess(state, timedOut, e.EngineId), null,
                                               5000, true);
    }

    public void DoPeriodicProcess(object state, bool timedOut, string engineId)
    {
        if (timedOut)
        {                
            Task.Factory.StartNew(engine.DoSomeWork); //Fire and forget
        }
    }
}


public class Engine
{
    public event EventHandler<WorkCompletedEventArgs> WorkCompleted;    
    public void DoSomeWork()
    {
        //Doing some work..

        //Raise an event to signal that the work has been completed
        var args = new WorkCompletedEventArgs {EngineId = Settings.EngineId};
        RaiseWorkCompletedEvent(args);
    }

    protected virtual void RaiseWorkCompletedEvent(WorkCompletedEventArgs e)
    {
        EventHandler<WorkCompletedEventArgs> handler = WorkCompleted;
        if (handler != null)
        {
            handler(this, e);
        }
    }   
}

When I run the code, the CPU usage shows 100% after few seconds. Upon debugging in VS, I see too many alive worker threads waiting at RegisterWaitForSingleObject inside WorkCompletedEventHandler.

Why aren't the threads dying after calling RegisterWaitForSingleObject? Am I missing something?

Sajal
  • 21
  • 2
  • Could you provide code that actually complies? In your code, the `engine` field is missing and the `QueueEmptied` event doesn't exist and is never subscribed. – svick Jun 13 '13 at 17:22
  • Updated the code to have WorkCompleted event handler. I subscribe to it in LoadSettings: engine.WorkCompleted += WorkCompletedEventHandler; – Sajal Jun 13 '13 at 17:49

1 Answers1

0

Not tested but I think this is due to the event not being reset:

private void WorkCompletedEventHandler(object sender, WorkCompletedEventArgs e)
{
    stopPeriodicProcess.Reset();
    ThreadPool.RegisterWaitForSingleObject(stopPeriodicProcess,
                                           (state, timedOut) => DoPeriodicProcess(state, timedOut, e.EngineId), null,
                                           5000, true);
}

Moreover I don't understand why you're doing things this way, can't you use a timer, which is precisely designed for this kind of use-case?

Pragmateek
  • 13,174
  • 9
  • 74
  • 108
  • This doesn't make any sense. In the code, `Set()` isn't called anywhere, so the event will never be set. – svick Jun 13 '13 at 17:20
  • I tried the reset. It didn't help. By timer, you mean System.Timers.Timer or System.Threading.Timer ? – Sajal Jun 13 '13 at 17:39