Service Threads

From RAD Studio
Jump to: navigation, search

Go Up to Service Applications

Each service has its own thread (Vcl.SvcMgr.TServiceThread), so if your service application implements more than one service you must ensure that the implementation of your services is thread-safe. TServiceThread is designed so that you can implement the service in the TService OnExecute event handler. The service thread has its own Execute method which contains a loop that calls the service's OnStart and OnExecute handlers before processing new requests.

Because service requests can take a long time to process and the service application can receive simultaneous requests from more than one client, it is more efficient to spawn a new thread (derived from System.Classes.TThread, not TServiceThread) for each request and move the implementation of that service to the new thread's Execute method. This allows the service thread's Execute loop to process new requests continually without having to wait for the service's OnExecute handler to finish. The following example demonstrates.

C++ Example

This service beeps every 500 milliseconds from within the standard thread. It handles pausing, continuing, and stopping of the thread when the service is told to pause, continue, or stop.

  1. Choose File > New > Other and double-click Service Application in the New Items dialog. The Service1 window appears.
  2. In your unit's header file, declare a new descendant of TThread named TSparkyThread. This is the thread that does the work for your service. The declaration should appear as follows:
    class TSparkyThread : public TThread {
    private: protected:
    	void __fastcall Execute();
    
    public:
    	__fastcall TSparkyThread(bool CreateSuspended);
    
    };
    
  3. In the .cpp file for your unit, create a global variable for a TSparkyThread instance:
    TSparkyThread *SparkyThread;
    
  4. Add the following code to the .cpp file for the TSparkyThread constructor:
    __fastcall TSparkyThread::TSparkyThread(bool CreateSuspended)
    	: TThread(CreateSuspended)
    {
    }
    
  5. Add the following code to the .cpp file for the TSparkyThread Execute method (the thread function):
    void __fastcall TSparkyThread::Execute() {
        while (!Terminated) {
            Beep();
            Sleep(500);
        }
    }
    
  6. Select the Service window (Service1), and double-click the OnStart event in the Object Inspector. Add the following OnStart event handler:
    void __fastcall TService1::Service1Start(TService *Sender, bool &Started) {
        SparkyThread = new TSparkyThread(false);
        Started = true;
    }
    
  7. Double-click the OnContinue event in the Object Inspector. Add the following OnContinue event handler:
    void __fastcall TService1::Service1Continue(TService *Sender, bool &Continued) {
        SparkyThread->Resume();
        Continued = true;
    }
    
  8. Double-click the OnPause event in the Object Inspector. Add the following OnPause event handler:
    void __fastcall TService1::Service1Pause(TService *Sender, bool &Paused) {
        SparkyThread->Suspend();
        Paused = true;
    }
    
  9. Finally, double-click the OnStop event in the Object Inspector and add the following OnStop event handler:
    void __fastcall TService1::Service1Stop(TService *Sender, bool &Stopped) {
        SparkyThread->Terminate();
        Stopped = true;
    }
    

Delphi Example

To create the example:

  1. Choose File > New > Other and double-click Service Application in the New Items dialog. The Service1 window appears.
  2. In the interface section of your unit, declare a new descendant of TThread named TSparkyThread. This is the thread that does the work for your service. The declaration should appear as follows:
     TSparkyThread = class(TThread)
       public
         procedure Execute; override;
     end;
    
  1. In the implementation section of your unit, create a global variable for a TSparkyThread instance:
  2.  var
       SparkyThread: TSparkyThread; // Add this code as the constructor
    
  3. In the implementation section for the TSparkyThread Execute method (the thread function), add the following code:
  4.  procedure TSparkyThread.Execute;
     begin
       while not Terminated do
       begin
         Beep;
         Sleep(500);
       end;
     end;
    
  5. Select the Service window (Service1), and double-click the OnStart event in the Object Inspector. Add the following OnStart event handler:
  6.  procedure TService1.Service1Start(Sender: TService; var Started: Boolean);
     begin
       SparkyThread := TSparkyThread.Create(False);
       Started := True;
     end;
    
  7. Double-click the OnContinue event in the Object Inspector. Add the following OnContinue event handler:
  8.  procedure TService1.Service1Continue(Sender: TService; var Continued: Boolean);
     begin
       SparkyThread.Resume;
       Continued := True;
     end;
    
  9. Double-click the OnPause event in the Object Inspector. Add the following OnPause event handler:
  10.  procedure TService1.Service1Pause(Sender: TService; var Paused: Boolean);
     begin
       SparkyThread.Suspend;
       Paused := True;
     end;
    
  11. Finally, double-click the OnStop event in the Object Inspector and add the following OnStop event handler:
  12.  procedure TService1.Service1Stop(Sender: TService; var Stopped: Boolean);
     begin
       SparkyThread.Terminate;
       Stopped := True;
     end;
    

When developing server applications, choosing to spawn a new thread depends on the nature of the service being provided, the anticipated number of connections, and the expected number of processors on the computer running the service.

See Also