目前,我正在用 C# 开发一系列 Windows 服务,它们使用计时器 (from System.Timers
) 来轮询它们正在运行的机器并将统计信息报告给远程侦听器(远程机器托管 WCF 数据服务)。
设置如下:我有一个用附加功能包装 System.Timers.Timer 的类,它接受一个通用事件处理程序,当计时器经过并记录信息时被触发:
public class GenericPoller
{
private EventLog _log;
private string _componentName;
private System.Timers.Timer _timer;
public GenericPoller
(
double interval,
System.Timers.ElapsedEventHandler handler,
EventLog log,
string componentName
)
{
_componentName = componentName;
_log = log;
_timer = new System.Timers.Timer();
_timer.Interval = interval;
_timer.AutoReset = true;
_timer.Enabled = false;
_timer.Elapsed += handler;
}
public void StartPolling()
{
try
{
_timer.Enabled = true;
_log.WriteEntry
(
"Timer started for component '" + _componentName
+ "', with " + _timer.Interval + "ms interval."
);
}
catch
{
_log.WriteEntry("Failed to start timer for component '" + _componentName + "'.");
}
}
public void StopPolling()
{
try
{
_timer.Enabled = false;
_log.WriteEntry("Timer stopped for component '" + _componentName + "'.");
}
catch
{
_log.WriteEntry("Failed to stop timer for component '" + _componentName + "'.");
}
}
}
我正在实现的任何一个服务都会GenericPoller
在它们的构造函数中创建一个,并且在OnStart
我通过一个单独的线程调用的方法中StartPolling
,以尽可能少地在这个方法中消耗时间。服务类大致如下所示:
public partial class CPUMonitor : ServiceBase
{
private GenericPoller _poller;
Thread _thread;
public CPUMonitor()
{
InitializeComponent();
_poller = new GenericPoller
(
HardwareMonitorCommon.Instance.DefaultPollingInterval,
PollCPU,
EventLog,
"CPUMonitor"
);
}
protected override void OnStart(string[] args)
{
_thread = new Thread(new ThreadStart(_poller.StartPolling));
_thread.Start();
}
protected override void OnStop()
{
_poller.StopPolling();
_thread.Join();
}
private void PollCPU(object sender, System.Timers.ElapsedEventArgs e)
{
Code to aqcuire CPU stats and report to WCF data service...
}
}
我使用installutil.exe
命令安装服务。服务有时会在分配的时间内无法启动(错误 1053),但似乎没有任何模式可以解决这个问题。10 次尝试中大约有 4 次尝试失败。
我简直无法理解为什么会发生这种情况。系统/应用程序事件日志没有报告服务进程的任何错误或异常,如果所有“繁重的工作”都发生在单独的线程中,我无法弄清楚为什么会发生超时。
我绝不是编写多线程代码的专业人士/专家,所以我完全期望做错事......我只是看不出它是什么......
编辑:该
Main
方法保留在自动生成的Program.cs
文件中,我只修改它以添加将运行的组件:
static class Program
{
/// <summary>
/// The main entry point for the application.
/// </summary>
static void Main()
{
ServiceBase[] ServicesToRun;
ServicesToRun = new ServiceBase[]
{
new CPUMonitor(),
new MemoryMonitor()
};
ServiceBase.Run(ServicesToRun);
}
}