Windows サービスとタイマーの使用に関連する多くの投稿を読みましたが、イベント ハンドラーがまだトリガーされている理由がわかりません。誰かが私を正しい方向に向けることができますか? なぜこれが起こっているのかを知りたいので、将来これを回避する方法を理解しています。
編集: onError イベント ハンドラーが呼び出されることはありません (または、イベント ログにイベントが表示されます)。
タイマー: System.Timers.Timer
ServiceBase: System.ServiceProcess.ServiceBase
抽象クラスは次のとおりです。
public abstract class ABCService : ServiceBase
{
// Members
protected Timer invocationTimer;
protected Timer wellnessTimer;
protected FileSystemWatcher fsw;
// Constructors
protected ABCService()
{
invocationTimer = new Timer();
wellnessTimer = new Timer();
fsw = null;
invocationTimer.AutoReset = false;
invocationTimer.Interval = 30000; // 30 seconds
invocationTimer.Elapsed += new ElapsedEventHandler(invocationTimer_Elapsed);
wellnessTimer.AutoReset = false;
wellnessTimer.Elapsed += new ElapsedEventHandler(wellnessTimer_Elapsed);
}
// Methods
protected void invocationTimer_Elapsed(object o, ElapsedEventArgs args)
{
try
{
// log to event log
invocationTimer.Stop();
if ((new FileInfo(fsw.Path + "\\" + fsw.Filter)).Exists)
{
onCreated(this, new FileSystemEventArgs(WatcherChangeTypes.Created, fsw.Path, fsw.Filter));
}
}
catch (Exception x)
{
onError(this, new ErrorEventArgs(x));
}
}
protected void wellnessTimer_Elapsed(object o, ElapsedEventArgs args)
{
try
{
// log to event log
wellnessTimer.Stop();
wellnessTimer.Interval = 60000; // ms
if (fsw != null)
{
fsw.Dispose();
}
fsw = new FileSystemWatcher(ConfigurationManager.AppSettings["pathKey"], ConfigurationManager.AppSettings["filterKey"]);
invocationTimer.Start();
}
catch (Exception x)
{
onError(this, new ErrorEventArgs(x));
}
}
protected abstract void onCreated(object o, FileSystemEventArgs args);
protected virtual void onError(object o, ErrorEventArgs args)
{
// log to event log
wellnessTimer.Start();
}
protected override void OnStart(string[] args)
{
// log to event log
wellnessTimer.Interval = 5000; // 5 seconds
wellnessTimer.Start();
}
protected override void OnStop()
{
// log to event log
wellnessTimer.Stop();
}
}
インスタンスクラスは次のとおりです。
public partial class Service1 : ABCService
{
// Members
private static object locket = new object();
private static DateTime LAST_RUN_TIME = DateTime.Now.AddSeconds(-10);
// Constructors
public Service1()
{
InitializeComponent();
}
// Methods
protected override void onCreated(object o, FileSystemEventArgs args)
{
lock (locket)
{
// log to event log
if ((DateTime.Now - LAST_RUN_TIME).Seconds >= 10)
{
// do stuff
}
else
{
// log to event log
invocationTimer.Stop();
invocationTimer.Start();
}
}
}
}
部分クラスの自動生成コードは次のとおりです。
partial class Service1
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Component Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
//
// Service1
//
this.ServiceName = "Service1";
}
#endregion
}
では、正確には何が起こっているのでしょうか。イベント ログを確認すると、1 分に 1 回、wellnessTimer イベント ハンドラが呼び出されていることがわかります。
これが私が起こっていると思うことですが、明らかに間違っています:
1. Service is started via MMC
2. OnStart() method is invoked
3. wellnessTimer interval is set to 5 seconds
4. wellnessTimer start method is invoked
5. wellnessTimer_Elapsed event handler is invoked
6. wellnessTimer stop method is invoked
7. wellnessTimer interval is set to 5 minutes
8. invocationTimer start method is invoked
9. 30 seconds later, the invocationTimer_Elapsed method is invoked
10. invocationTimer stop method is invoked
この時点で、両方のタイマーがこのインスタンスにまだ存在している必要がありますが、無効にする必要があります。これを Visual Studio 2010 のプロセスにアタッチしてデバッグし、イベント ハンドラーに渡されるオブジェクト (送信者) の ID をマークしました。インスタンスと同じオブジェクトです。また、[ローカル] ウィンドウの両方のタイマーで、有効なプロパティが false に設定されていました。
これにより、継承を正しく使用していないか、スレッドで何かが起こっていることがわかります。私はどちらも得意ではありませんが、それが原因である場合は教えてください。学べます。
事前にみんなに感謝します。
編集#2:ここにいくつかのトレースデータがあります...
「o」は、イベント ハンドラに渡されるオブジェクトを表します
ABCService() method invoked <--
ABCService() method invoked -->
Service1() method invoked <--
Service1() method invoked -->
OnStart() method invoked <--
OnStart() method invoked -->
wellnessTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled = False
((System.Timers.Timer) o).Interval = 5000
this.wellnessTimer.Enabled = False
this.wellnessTimer.Interval = 5000
wellnessTimer_Elapsed() method invoked -->
invocationTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled = False
((System.Timers.Timer) o).Interval = 30000
this.invocationTimer.Enabled = False
this.invocationTimer.Interval = 30000
invocationTimer_Elapsed() method invoked -->
wellnessTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled = False
((System.Timers.Timer) o).Interval = 60000
this.wellnessTimer.Enabled = False
this.wellnessTimer.Interval = 60000
wellnessTimer_Elapsed() method invoked -->
invocationTimer_Elapsed() method invoked <--
((System.Timers.Timer) o).Enabled = False
((System.Timers.Timer) o).Interval = 30000
this.invocationTimer.Enabled = False
this.invocationTimer.Interval = 30000
invocationTimer_Elapsed() method invoked -->