【发布时间】:2010-11-17 11:01:24
【问题描述】:
我目前正在构建一个 Windows 服务,该服务需要处理位于数据库表中的消息队列。该队列的长度可能不同,并且可能需要 5 秒到 55 秒来针对数据库中的所有行执行(我目前正在使用包含 500,000 条记录的测试数据集)
Windows 服务配置为在 30 秒计时器上运行,因此我尝试确保在计时器委托运行时它无法再次运行,直到对方法的上一个请求成功完成后才能再次运行
p>我的 Windows 服务 OnStart 方法中有以下代码:
AutoResetEvent autoEvent = new AutoResetEvent(false);
TimerCallback timerDelegate = new TimerCallback(MessageQueue.ProcessQueue);
Timer stateTimer = new Timer(timerDelegate, autoEvent, 1000, Settings.Default.TimerInterval); // TimerInterval is 30000
autoEvent.WaitOne();
MessageQueue.ProcessMessage 中的代码如下:
Trace.Write("Starting ProcessQueue");
SmtpClient smtp = new SmtpClient("winprev-01");
AutoResetEvent autoEvent = (AutoResetEvent)stateObject;
foreach (MessageQueue message in AllUnprocessed)
{
switch (message.MessageType)
{
case MessageType.PlainText:
case MessageType.HTML:
SendEmail(smtp, message);
break;
case MessageType.SMS:
SendSms(message);
break;
default:
break;
}
}
autoEvent.Set();
Trace.Write("Ending ProcessQueue");
我正在使用 DebugView 在服务运行时分析 Trace 语句的视图,我可以看到每 30 秒发生一次的多个“Starting ProcessQueue”实例,这是我试图避免发生的情况
总结:我想调用 ProcessQueue 并确保它不会再次执行,除非它完成了它的工作(这使我能够防止队列中的相同消息被多次处理
我确定我在这里遗漏了一些非常明显的东西,所以任何帮助将不胜感激:)
戴夫
【问题讨论】:
-
为什么不在 MessageQueue.ProcessMessage 方法的开头和结尾设置一个锁/触发器,然后在再次调用 ProcessQueue 之前检查它?
-
@Bolu:这不是一个好主意。他的代码迭代基本上是排队、阻塞、等待第一个完成——然后大概他们每个人都会依次运行,然后无事可做。
-
你真正想要的是一个同步定时器对象——在 Win32 中,它被称为可等待定时器。
-
@Andrew,当我说锁定/触发器时,我的意思是一个简单的布尔值......在启动 ProcessQueue 时将其设置为 false,并在完成时将其设置为 true,其他迭代只需检查它并爆发(如果是假的)
-
其实,如果他要在这里使用定时器,他应该只触发一次,并且只有在工作完成时才重置定时器......根本不使用ResetEvent。
标签: c# multithreading windows-services