C# Threading.Timer 在 windows 服务任务中并不总是触发
C# Threading.Timer not always triggering when in a windows Service Task
伙计们,我正在 Windows 基于 .NET 的服务中实施一个例程,并在
中使用 Threading.Timer 任务
protected override void OnStart(string[] args)
{
base.OnStart(args);
_startupTask = Task.Factory.StartNew(StartupAction, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
在我的 StartupAction 中,我定义 Threading.Timer 如下:
private void StartupAction()
{
System.Threading.Timer infamousTimer;
infamousTimer = new System.Threading.Timer(new TimerCallback(runMeEveryHour), null, new TimeSpan(0), new TimeSpan(1, 0, 0));
}
有人会认为这很简单,但由于某种原因它并不总是有效(在某些 PC 上有效但在其他 PC 上无效)。
谁知道罪魁祸首或环境依赖性是什么?
谢谢
当计时器超出范围时,不会触发回调。请参阅下面的答案
您的问题在于您使用 Task
并创建完全包含在任务操作中的计时器:
private void StartupAction()
{
System.Threading.Timer infamousTimer;
infamousTimer = new System.Threading.Timer(new TimerCallback(runMeEveryHour), null, new TimeSpan(0), new TimeSpan(1, 0, 0));
}
我认为发生的事情是一旦 StartupAction
完成计时器超出范围并且 disposed/GC'd。
改为将定时器变量移到外面:
private Timer infamousTimer;
private void StartupAction()
{
infamousTimer = new System.Threading.Timer(new TimerCallback(runMeEveryHour), null, new TimeSpan(0), new TimeSpan(1, 0, 0));
}
这里的优点还在于OnStop
你可以干净利落地处理计时器。
当然,为什么还要在 Task
中执行此操作?似乎在 OnStart
中这样做也同样有效。
我还想指出,如果所有服务所做的只是 运行 一个计时器,那么您最好安排一个计划任务,但我在那里做了一个假设。
请参阅 this blog post 了解原因。
我认为您的 StartupAction 方法即将结束(在我看来,它超出范围并收集垃圾是一个副产品)。
您需要修改 StartupAction 方法以使其保持活动状态。
尝试添加如下内容:while(true) { Thread.Sleep(1000); }
以保持线程活跃。
private void StartupAction()
{
System.Threading.Timer infamousTimer;
infamousTimer = new System.Threading.Timer(new TimerCallback(runMeEveryHour), null, new TimeSpan(0), new TimeSpan(1, 0, 0));
while(true) { Thread.Sleep(1000); } //this is the simplest logic to keep the thread alive
}
当计时器超出范围时,不会触发回调。
伙计们,我正在 Windows 基于 .NET 的服务中实施一个例程,并在
中使用 Threading.Timer 任务protected override void OnStart(string[] args)
{
base.OnStart(args);
_startupTask = Task.Factory.StartNew(StartupAction, CancellationToken.None, TaskCreationOptions.LongRunning, TaskScheduler.Default);
}
在我的 StartupAction 中,我定义 Threading.Timer 如下:
private void StartupAction()
{
System.Threading.Timer infamousTimer;
infamousTimer = new System.Threading.Timer(new TimerCallback(runMeEveryHour), null, new TimeSpan(0), new TimeSpan(1, 0, 0));
}
有人会认为这很简单,但由于某种原因它并不总是有效(在某些 PC 上有效但在其他 PC 上无效)。
谁知道罪魁祸首或环境依赖性是什么?
谢谢
当计时器超出范围时,不会触发回调。请参阅下面的答案
您的问题在于您使用 Task
并创建完全包含在任务操作中的计时器:
private void StartupAction()
{
System.Threading.Timer infamousTimer;
infamousTimer = new System.Threading.Timer(new TimerCallback(runMeEveryHour), null, new TimeSpan(0), new TimeSpan(1, 0, 0));
}
我认为发生的事情是一旦 StartupAction
完成计时器超出范围并且 disposed/GC'd。
改为将定时器变量移到外面:
private Timer infamousTimer;
private void StartupAction()
{
infamousTimer = new System.Threading.Timer(new TimerCallback(runMeEveryHour), null, new TimeSpan(0), new TimeSpan(1, 0, 0));
}
这里的优点还在于OnStop
你可以干净利落地处理计时器。
当然,为什么还要在 Task
中执行此操作?似乎在 OnStart
中这样做也同样有效。
我还想指出,如果所有服务所做的只是 运行 一个计时器,那么您最好安排一个计划任务,但我在那里做了一个假设。
请参阅 this blog post 了解原因。
我认为您的 StartupAction 方法即将结束(在我看来,它超出范围并收集垃圾是一个副产品)。
您需要修改 StartupAction 方法以使其保持活动状态。
尝试添加如下内容:while(true) { Thread.Sleep(1000); }
以保持线程活跃。
private void StartupAction()
{
System.Threading.Timer infamousTimer;
infamousTimer = new System.Threading.Timer(new TimerCallback(runMeEveryHour), null, new TimeSpan(0), new TimeSpan(1, 0, 0));
while(true) { Thread.Sleep(1000); } //this is the simplest logic to keep the thread alive
}
当计时器超出范围时,不会触发回调。