サービス スレッド
[サービス アプリケーション] への移動
サービスは、それぞれに自身のスレッド(Vcl.SvcMgr.TServiceThread)を持ちます。そのため、サービス アプリケーションで複数のサービスを実装する場合には、サービスがスレッドセーフになるよう実装しなければなりません。TServiceThread は、サービスを TService の OnExecute イベント ハンドラで実装できるように設計されています。サービス スレッドには独自の Execute メソッドがあり、その中のループでは、サービスの OnStart ハンドラと OnExecute ハンドラを呼び出してから新しい要求を処理します。
サービス要求の処理には長い時間がかかる可能性があり、サービス アプリケーションが複数のクライアントから同時に要求を受け取る可能性もあるため、要求ごとに新しいスレッド(TServiceThread ではなく System.Classes.TThread から派生したもの)を生成し、サービスの実装を新しいスレッドの Execute メソッドに移動する方が効率的です。こうすることで、サービス スレッドの Execute ループで新しい要求を継続的に処理できるようになり、サービスの OnExecute ハンドラの処理が終了するのを待つ必要がなくなります。以下に例を示します。
C++ の例
このサービスは、標準スレッド内から 500 ミリ秒ごとにビープ音を鳴らします。一時停止、再開、終了を指示されると、スレッドを一時停止、再開、終了するよう処理します。
- [ファイル|新規作成|その他...]を選択し、[新規作成]ダイアログの[サービス アプリケーション]をダブルクリックします。Service1 のウィンドウが開きます。
-
ユニットのヘッダー ファイルで、TThread の新しい下位クラスを TSparkyThread という名前で宣言します。これがサービスの仕事を行うスレッドです。宣言は次のようになります。
class TSparkyThread : public TThread { private: protected: void __fastcall Execute(); public: __fastcall TSparkyThread(bool CreateSuspended); };
-
ユニットの .cpp ファイルで、TSparkyThread インスタンスを保持するためのグローバル変数を作成します。
TSparkyThread *SparkyThread;
-
.cpp ファイルの TSparkyThread のコンストラクタに以下のコードを追加します。
__fastcall TSparkyThread::TSparkyThread(bool CreateSuspended) : TThread(CreateSuspended) { }
-
.cpp ファイルの TSparkyThread の Execute メソッド(スレッド関数)に以下のコードを追加します。
void __fastcall TSparkyThread::Execute() { while (!Terminated) { Beep(); Sleep(500); } }
-
Service ウィンドウ(Service1)を選択し、[オブジェクト インスペクタ]で OnStart イベントをダブルクリックします。以下の OnStart イベント ハンドラを追加します。
void __fastcall TService1::Service1Start(TService *Sender, bool &Started) { SparkyThread = new TSparkyThread(false); Started = true; }
-
[オブジェクト インスペクタ]で OnContinue イベントをダブルクリックします。以下の OnContinue イベント ハンドラを追加します。
void __fastcall TService1::Service1Continue(TService *Sender, bool &Continued) { SparkyThread->Resume(); Continued = true; }
-
[オブジェクト インスペクタ]で OnPause イベントをダブルクリックします。以下の OnPause イベント ハンドラを追加します。
void __fastcall TService1::Service1Pause(TService *Sender, bool &Paused) { SparkyThread->Suspend(); Paused = true; }
-
最後に、[オブジェクト インスペクタ]で OnStop イベントをダブルクリックし、以下の OnStop イベント ハンドラを追加します。
void __fastcall TService1::Service1Stop(TService *Sender, bool &Stopped) { SparkyThread->Terminate(); Stopped = true; }
Delphi の例
例を作成するには:
- [ファイル|新規作成|その他...]を選択し、[新規作成]ダイアログの[サービス アプリケーション]をダブルクリックします。Service1 のウィンドウが開きます。
- ユニットの interface セクションで、TThread の新しい下位クラスを TSparkyThread という名前で宣言します。これがサービスの仕事を行うスレッドです。宣言は次のようになります。
- ユニットの implementation セクションで、TSparkyThread インスタンスを保持するためのグローバル変数を作成します。
- TSparkyThread の Execute メソッド(スレッド関数)の implementation セクションに以下のコードを追加します。
- Service ウィンドウ(Service1)を選択し、[オブジェクト インスペクタ]で OnStart イベントをダブルクリックします。以下の OnStart イベント ハンドラを追加します。
- [オブジェクト インスペクタ]で OnContinue イベントをダブルクリックします。以下の OnContinue イベント ハンドラを追加します。
- [オブジェクト インスペクタ]で OnPause イベントをダブルクリックします。以下の OnPause イベント ハンドラを追加します。
- 最後に、[オブジェクト インスペクタ]で OnStop イベントをダブルクリックし、以下の OnStop イベント ハンドラを追加します。
TSparkyThread = class(TThread)
public
procedure Execute; override;
end;
var
SparkyThread: TSparkyThread; // Add this code as the constructor
procedure TSparkyThread.Execute;
begin
while not Terminated do
begin
Beep;
Sleep(500);
end;
end;
procedure TService1.Service1Start(Sender: TService; var Started: Boolean);
begin
SparkyThread := TSparkyThread.Create(False);
Started := True;
end;
procedure TService1.Service1Continue(Sender: TService; var Continued: Boolean);
begin
SparkyThread.Resume;
Continued := True;
end;
procedure TService1.Service1Pause(Sender: TService; var Paused: Boolean);
begin
SparkyThread.Suspend;
Paused := True;
end;
procedure TService1.Service1Stop(Sender: TService; var Stopped: Boolean);
begin
SparkyThread.Terminate;
Stopped := True;
end;
サーバー アプリケーションを開発する場合には、提供するサービスの性質、接続数の予想、サービスを実行するコンピュータ上のプロセッサ数の予想を基に、新しいスレッドを生成するかどうかを選択します。