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
| CSharp-Online.NET:Articles |
| .NET Articles |
|
| © 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)); } }
|

