2009-07-02 28 views
6

Windowsサービスの作成時にベストプラクティスがあるかどうかを確認するだけです。 、その後、ループ内で時間を確認Windowsサービス:指定された時間に作業する(Delphi)

  1. 利用スリープ():

    サービス(シングルスレッド)が、今私は考えることができ、指定した時間間隔で動作する必要が?

  2. TTimerを使用しますか?

アドバイスはありますか?

答えて

10

これはサービスである必要がありますか? Windowsでスケジュールされたタスクをセットアップできますか?

+0

最初の質問にも心に来ました。 http://weblogs.asp.net/jgalloway/archive/2005/10/24/428303.aspx – ilitirit

+0

興味深い読書。それは非常に有効なポイントを持っているので、いくつかのコメントをしてください。私はこの引用が特に好きです: "同じことをするあなた自身のロールを作るよりも既存のサービスを使う方が良いですが、Windowsタスクスケジューラはうんざりです。"だから、はい、タスクスケジューラが最初に試してみてください、そしてサービスを書くことは極端な場合にのみ行われるべきです。しかし、これらのケースが存在し、私は長い間、タスクスケジューラーサービスと戦った後にのみ、スケジューリングサービスを書いて、最終的にそれが多用途ではないということを受け入れなければならなかった。 – mghie

3

私はスリープを使用します。

両方のオプションには正確な時間保証はありませんが、スリープではリソースが他のプロセスに返されます。

+1

タイマメッセージは、メッセージループで使用される、キューにメッセージがない場合のGetMessage()はブロックしません。リソースはいずれにせよ浪費されません。 – mghie

13

本当にサービスがそのコードは常に別のスレッドのコンテキストで呼び出されていますとしてあなたのサービスは、シングルスレッドであることは重要ではありません。

  • サービスマネージャは、開始、停止、一時停止、再開しますサービスの実行を開始し、現在のサービス状態を要求します。

  • サービス自体には、サービスマネージャからの要求に反応し、要求されたサービス実行状態を変更し、要求された情報を返す必要がある、実際の作業を行う少なくとも1つのスレッドがあります。サービスは、合理的に短期間でService Managerからの要求に対応する必要があります。そうでなければ、サービスが停止して終了すると見なします。そのため、サービスの実行時間が長くなったり、コードがブロックされたりすると、複数のサービススレッドを持つ方が良いかもしれません。 スリープ()またはタイマーメッセージを使用するかどうかを

また、サービススレッドのメッセージポンプの可用性に依存しません。メッセージポンプがない場合は、Sleep()またはタイマーコールバックを使用する必要があります。とにかくメッセージポンプを持っているのであれば、Windowsメッセージ経由で他のプロセスやスレッドと通信する必要があるか、OLEを行う必要があるため、タイマーメッセージを使用するのが最も簡単です。

数年前、私はWindows atやUnix cronの機能に似た、タスクのタイムリーなバックグラウンド実行のためのサービスを書きました。 VCLの多くは使用せず、いくつかの基本クラスのみを使用します。サービスのラン()メソッドは次のようになります、

procedure TScheduleService.Run; 
var 
    RunState: TServiceRunState; 
begin 
    while TRUE do begin 
    RunState := GetServiceRunState; 
    if (RunState = srsStopped) or (fEvent = nil) then 
     break; 
    if RunState = srsRunning then begin 
     PeriodicWork; 
     Sleep(500); 
    end else 
     fEvent.WaitFor(3000); 
    Lock; 
    if fServiceRunStateWanted <> srsNone then begin 
     fServiceRunState := fServiceRunStateWanted; 
     fServiceRunStateWanted := srsNone; 
    end; 
    Unlock; 
    end; 
end; 

これはスリープ()ループ内を使用していますが、

while integer(GetMessage(Msg, HWND(0), 0, 0)) > 0 do begin 
    TranslateMessage(Msg); 
    DispatchMessage(Msg); 
end; 

を使用したソリューションは、同じようにうまくいくだろうとWindowsのタイマーメッセージを使用することができます。

+0

あなたが本当に必要でない限り、私はメッセージループを避けるでしょう。最初のループは基本的に私がスレッドではありません。 – mj2008

3

TTimerはスレッドセーフではありません。あなたがスレッドでTTimerのようなアプローチを使用する必要がある場合、私はDSiWin32からTDSiTimerを提案したいと思います。

2

サービスでTTimerを使用しないでください。期待どおりに動作するとは限りません。スレッドセーフではありません。

サービス内では、自分の時間間隔変数を常に使用し、タスク実行時間の間にスリープします。応答可能なサービスを維持するために、通常1-2000 msの短い時間スリープしてから、メッセージを処理してから、「タスク」を実行する時間かどうかを確認します。まだ時間がない場合は、スリープ状態に戻り、ループの後に再度確認してください。このようにして、リソースを戻しますが、次のタスクが実行される前にユーザーの入力(停止、一時停止)に応答することもできます。私はサービスでこのようなものを使用alwasy

0

:もちろん

unit uCopy; 

interface 

uses 
    Windows, Messages,.......; 

procedure MyTimerProc(hWindow : HWND; uMsg : cardinal; idEvent : cardinal; dwTime : DWORD); stdcall; 

type 
    TFileCopy= class(TService) 
    procedure ServiceStart(Sender: TService; var Started: Boolean); 
    procedure ServiceStop(Sender: TService; var Stopped: Boolean); 
    private 
    { Private declarations } 
    public 
     { Public declarations } 
    end; 

VAR 
    timerID : UINT; 

const 
SECONDS = 900000; 

procedure TFileCopy.ServiceStart(Sender: TService; 
    var Started: Boolean); 
Begin 
timerID := 0; //Probably not needed. 
timerID := SetTimer(0, 1, SECONDS, @MyTimerProc); 
End; 

procedure MyTimerProc(hWindow : HWND; uMsg : cardinal; idEvent : cardinal;dwTime : DWORD); stdcall; 
Begin 
    //Kill timer while trying.. If this function takes longer than the interval to run, I didn't want a build up. If that was possible. 
    KillTimer(0, timerID); 
    timerID := 0; //Is it needed? 
//DO WORK. 
{ 
//I was Connecting to a Network Drive, Minutes, seconds..... 
//I only wanted to run this Every day at 2 AM. 
//So I had my timer set to 15 minutes, once it got between 30 and 10 minutes of my 2 AM deadline, 
//i killed the existing timer and started a new one at 60000. 
//If it was within 10 minutes of my 2 AM, my interval changed to 500. 
//This seems to work for me, my files get copied everyday at 2 AM. 
} 
//Work Complete. Start timer back up. 
    timerID := SetTimer(0, 1, SECONDS, @MyTimerProc); 
End; 

procedure TFileCopy.ServiceStop(Sender: TService; 
    var Stopped: Boolean); 
Begin 
if timerID > 0 then 
    KillTimer(0, timerID); 
End; 

は、私が持っている ....ログへの書き込みと電子メールで送信するとともに、ほとんどの場所でいくつかのtry..catchを持っていましたこれらの技術を使って1年以上サービスを実行しています。 それは決してルールではありません。 もっと良い方法があるか教えてください。 私はDelphiの知識を向上させる方法を常に探しています。 また、質問に投稿する期限が間に合わなかった場合は、申し訳ありません。

-Trey Aughenbaugh

関連する問題