将服务与计时器同步
我正在尝试用 c# 编写一个服务,该服务应该从给定日期开始按给定间隔(超时)运行。如果该日期是将来的日期,则服务应等到到达日期时间才启动。
示例:
-
如果我将超时设置为 21:00:00 起 1 小时,我希望程序每小时运行一次
如果我将超时设置为从 3999.01.01 21:00:00 开始的 1 小时,我希望程序在该日期之前每小时运行一次
我已经通过以下代码实现了这一点,但它有一些问题!
-
当我安装服务(使用 installutil)时,由于“Thread.Sleep()”,服务被标记为启动。该服务似乎挂起并正在“安装”直到启动。
-
“ServiceTimer_Tick()”内的代码可能需要比预期超时更长的时间。如果发生这种情况,如何防止计时器堆栈增加?
我想到的替代方案:
-
包括第一次使用“timeout.Interval”,然后在后续调用中重置它,但感觉不对。
-
我还考虑过放弃整个服务理念并将其编译为可执行文件并设置计划任务。
我
缩短的示例:
public Service()
{
_timeout = new TimeSpan(0,1,0,0);
_timer = new System.Timers.Timer();
_timer.Interval = _timeout.TotalMilliseconds;
_timer.Elapsed += new ElapsedEventHandler(ServiceTimer_Tick);
}
private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e)
{
lock (_obj)
{
// Stuff that could take a lot of time
}
}
public static void Main()
{
Run(new Service());
}
protected override void OnStart(string[] args)
{
long current = DateTime.Now.Ticks;
long start = new DateTime(2010,9,15,21,0,0).Ticks;
long timeout = _timeout.Ticks;
long sleep;
if (current > start)
sleep = timeout - ((current % timeout)) + (start % timeout);
else
sleep = start - current;
Thread.Sleep(new TimeSpan(sleep));
_timer.AutoReset = true;
_timer.Enabled = true;
_timer.Start();
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
使用 System.Threading.Timer 可以更轻松地实现这一点。您可以告诉它在第一次滴答之前等待多长时间,然后告诉它之后滴答的频率。
因此,如果您想在开始前等待 2 天,然后每小时执行一次操作,您可以这样写:
也就是说,如果这是每小时只需运行一次的操作,那么听起来您真正想要的是然后您可以使用 Windows 任务计划程序安排一个可执行文件。
This is easier with a
System.Threading.Timer
. You can tell it how long to wait before the first tick, and then how often to tick after that.So, if you wanted to wait 2 days before starting, and then do something once per hour, you'd write:
That said, if this is something that only has to run once per hour, then it sounds like what you really want is an executable that you then schedule with Windows Task Scheduler.
您可以使用
System.Threading.Timer
。它支持dueTime
和period
这正是您所需要的。You can use a
System.Threading.Timer
. It supports both adueTime
and aperiod
which is just what you need.您必须将计时器逻辑移动到从 OnStart 例程生成的单独线程中。那么你的逻辑就不能干扰SCM,服务就会正常启动。
编辑:只是为了详细说明 - 对于此任务,我认为计时器工作得不太好,因为您没有考虑时钟校正,这可能导致偏差(或者如果用户手动更改时钟时间,甚至是不正确的)。这就是为什么在我看来,与小间隔的时钟时间进行比较是首选的原因。
该线程的 Run 例程可能如下所示:
you have to move the timer logic to a separate thread that you spawn from your OnStart routine. Then your logic cannot interfere with the SCM and the service will start normally.
Edit: Just to elaborate - for this task I don't think timers work very well, since you are not taking clock corrections into account which could lead to a skew (or even be incorrect if the user manually changes the clock time). That's why comparing to the clock time in small intervals is imo preferred.
The
Run
routine of that thread could look like this: