Creating a .NET Windows Service—Alternative 2: Use Multiple Threads

Microsoft .NET Framework, ASP.NET, Visual C# (CSharp, C Sharp, C-Sharp) Developer Training, Visual Studio


Jump to: navigation, search
CSharp-Online.NET:Articles
.NET Articles

Create .NET Windows Service

© 2005 Pearson Education, Inc.

Alternative 2: Use Multiple Threads

This technique is very similar to the single-thread alternative discussed previously, but extends it to use multiple threads. This pattern can easily replace the single-thread alternative, by using just one thread in the array. Let's jump into the code. First, we declare class-level variables, as shown in Listing 9.

Listing 9 Class-level variables for the multithreaded approach.

// array of worker threads
Thread[] workerThreads;
 
// the objects that do the actual work
Worker[] arrWorkers;
 
// number of threads; typically specified in config file
int numberOfThreads = 2;

Listing 10 shows the OnStart event.

Listing 10 OnStart method for the multithreaded approach.

protected override void OnStart(string[] args)
{
   arrWorkers = new Worker[numberOfThreads];
   workerThreads = new Thread[numberOfThreads];
   for (int i =0; i < numberOfThreads; i++)
   {
      // create an object
      arrWorkers[i] = new Worker(i+1, EventLog);
 
      // set properties on the object
      arrWorkers[i].ServiceStarted = true;
 
      // create a thread and attach to the object
      ThreadStart st = new ThreadStart(arrWorkers[i].ExecuteTask);
      workerThreads[i] = new Thread(st);
   }
 
   // start the threads
   for (int i = 0; i < numberOfThreads; i++)
   {
      workerThreads[i].Start();
   }
}

First we create an array of Worker objects of the required size. Worker is a separate class containing an ExecuteTask method that does all the work. Then we declare an array of threads and attach one Worker object to each thread, specifying ExecuteTask as the method to be called. Finally, we start all the threads. After that, the OnStart method completes and control returns to Windows.

The ExecuteTask method is similar to the worker methods shown in the earlier examples (see Listing 11).

Listing 11 Worker method for the multithreaded approach.

public void ExecuteTask()
{
   DateTime lastRunTime = DateTime.UtcNow;
 
   while (serviceStarted)
   {
   // check the current time against the last run plus interval
   if ( ((TimeSpan) 
      (DateTime.UtcNow.Subtract(lastRunTime))).TotalSeconds >= _interval)
   {
      // if time to do something, do so
      // exception handling omitted here for simplicity
      _serviceEventLog.WriteEntry(
         "Multithreaded Service working; id = " + this._id.ToString(),
            EventLogEntryType.Information);
 
      // set new run time
      lastRunTime = DateTime.UtcNow;
   }
 
   // yield
   if (serviceStarted)
   {
      Thread.Sleep(new TimeSpan(0,0,15));
   }
}
 
 Thread.CurrentThread.Abort();
}

Notice that we use a smaller interval for the Thread.Sleep method (15 seconds) to increase responsiveness when the service is stopped. If we didn't do this, the service would be blocked until the _interval period was complete (or would simply time out if the interval was too long).

The OnStop event is very similar to the one we discussed for the single-thread method, except here it has to signal all the threads to stop, as shown in Listing 12.

Listing 12 OnStop method for the multithreaded approach.

protected override void OnStop()
{
   for (int i = 0; i < numberOfThreads; i++)
   {
      // set flag to stop worker thread
      arrWorkers[i].ServiceStarted = false;
 
      // give it a little time to finish any pending work
     workerThreads[i].Join(new TimeSpan(0,2,0));
   }
}


Previous_Page_.gif Next_Page_.gif

Today's Deals: Electronics

Personal tools