3

I made this small windows service in c# and I believe I may have done something wrong with my ThreadPool code that prevents my Windows Service from completely starting. If you must know, the windows service seems to be running perfectly only that when looked upon the Services console, it still states that it is "starting". When I restarted my server, the service seem to have stopped again even though I have set it to Automatic startup.

Please see my code below:

protected override void OnStart(string[] args)
{
     int itemCount = itemList.Count;

     this.doneEvents = new ManualResetEvent[itemCount];
     for (int i = 0; i < itemCount; i++)
     {
         int oId = this.itemList[i];
         this.doneEvents[i] = new ManualResetEvent(false);

         ThreadPool.QueueUserWorkItem(data =>
         {
             while (this.activated)
             {
                 DateTime start = DateTime.Now;

                 // my code here

                 // choke point
                 TimeSpan duration = (DateTime.Now - start);
                 if (duration.Milliseconds < CONST_WAITMILLISECONDS)
                    Thread.Sleep((CONST_WAITMILLISECONDS - duration.Milliseconds));
              }

              this.doneEvents[i].Set(); // thread done

            }, oId);
         }

         WaitHandle.WaitAll(doneEvents);

}
Martin Ongtangco
  • 22,657
  • 16
  • 58
  • 84
  • 1
    you have to code to one level of indirection. The call to `OnStart()` **must** return in a timely fashion (e.g., within 30 seconds or so). Otherwise, the OS will kill the service. Thus, you need to put the logic currently in your `OnStart()` method in a thread spawned by `OnStart()`, i.e., one level of indirection. – Matt Davis Jun 08 '11 at 03:09

2 Answers2

3

You are blocking the OnStart call by WaitHandle.WaitAll(doneEvents);. Windows tries to start the service but times out because of WaitAll.

You need to let OnStart complete if you want Windows to treat the service as started.

Alex Aza
  • 76,499
  • 26
  • 155
  • 134
  • hi, thanks for the quick response. what would be the better solution? – Martin Ongtangco Jun 08 '11 at 00:22
  • but i need this logic to constantly run the loop throughout its life. am i doing it wrong? – Martin Ongtangco Jun 08 '11 at 00:32
  • 2
    It will be constantly running if you just remove WaitAll. Try this. – Alex Aza Jun 08 '11 at 00:33
  • i removed the Wait handle, the service stops after that. – Martin Ongtangco Jun 08 '11 at 00:46
  • You need to show more code with more detailed explanation on what you're trying to achieve. – Alex Aza Jun 08 '11 at 00:50
  • i wanted this service to constantly check a web service api to synchronize data. I need this to loop throughout its life unless I stop the service itself. My previous code works definitely; but I feel that I made the wrong execution that's why the ThreadPool is preventing the service to loop again. I could go for timers, but i never preferred that for obvious reasons that I have to handle that as well. – Martin Ongtangco Jun 08 '11 at 00:53
  • Not sure I understand `obvious reasons`, but if you need to check something periodically timer is exactly what you need. – Alex Aza Jun 08 '11 at 00:54
  • @Alex: You can't do this in OnStart. Start a separate thread to do your polling for the life of the service in OnStart, and then shut it down during OnStop. – Joe Jun 08 '11 at 01:30
  • @Joe - There is `ThreadPool.QueueUserWorkItem` in OnStart. This will be run in a separate service. Trust me I do know how OnStart and OnStop works :). – Alex Aza Jun 08 '11 at 01:32
  • @Martin Ongtangco, the reason the service stops when you remove the `WaitAll()` call is because `ThreadPool` threads are background threads and are not sufficient for keeping the process alive. If there is not at least one foreground thread running, the CLR will terminate the process, i.e., your service. In the accepted answer, the `Thread` object is a foreground thread by default and is thus capable of keeping the service alive until it is terminated in the `OnStop()` call. – Matt Davis Jun 08 '11 at 22:58
2

I think you could wrap the logic inside OnStart in a thread. This thread would be closed when you received an OnStop event.

Something like this:

Thread _ServiceThread;
protected override void OnStart(string[] args) { 
    _ServiceThread = new Thread(() => { /* your current OnStart logic here...*/ });
    _ServiceThread.Start();
}
protected override void OnStop() {
    _ServiceThread.Stop();
}
Vladimir
  • 264
  • 1
  • 3