我有一个Windows Service类(继承自ServiceBase),它在构造时提供了一个对象列表。
每个操作描述一个DoWork()虚拟方法
Service类的重点是管理所有底层操作,在运行时将它们添加到List中并在ThreadPool线程中执行它们的DoWork()方法。
每个Operation都有一个System.Timers.Timer对象,该对象被实例化并与Operation类一起运行。每个操作都会公开一个事件,通知管理类自己的计时器已启动,并且必须在线程中触发自己的DoWork()方法。
TimedService类将每个已用的计时器事件绑定到从池请求线程的方法:
private void CheckOperationsList(object source, EventArgs e)
{
try
{
foreach (Operation op in this._operationsList)
{
lock (this._operationsList)
{
op.TimerElapsed += new Operation.ElapsedEventHandler(this.RequestThreadFromPool);
}
}
}
catch (Exception ex) { this._ManEV.WriteError(this._serviceName, ex.Message); }
}
当然,RequestThreadFromPool(对象发送者,EventArgs e)方法执行以下操作:
ThreadPool.QueueUserWorkItem(new WaitCallback(((Operation)sender).DoWork), new object());
我从流程中收到了奇怪的行为。我试图实现一个虚拟操作,定时器设置为10秒,这只是让处理器占用几秒钟:
for (Int16 i = 0; i < Int16.MaxValue; i++)
{
for (short j = 0; j < short.MaxValue; j++)
{ }
}
每次操作在队列中单独运行时(我只将一个元素的List传递给服务)一切正常。该过程产生自己的线程,使CPU保持几秒钟,然后离开。
我实现了上面的虚拟方法的较轻版本(基本上没有内部循环)以模拟轻量级线程。
一旦我在队列中得到两个或更多个操作(使用不同的计时器!),所有线程都会产生三到四次,然后一切都停止。
我根本没有活动。在Visual Studio中,看起来每个操作的Timer都已停止滴答 - 我没有调用该事件,我没有调用应该处理该事件的委托;每个Operation类都有自己的定时器,并且总是通过它来引用定时器。 !
我尝试监控所有catch {} es,并尝试在try {}中包装每个DoWork()方法,但我没有例外。
让我感到困惑的是,如果我运行几个相同的操作(即两个或三个长操作或两个或三个短操作),一切都正常运行。看起来事件来自另一个类,一切都搞砸了。
我开始认为System.Timers.Timer类是上述所有原因 - 我在调用Event之前尝试将Stop()调用到计时器,但无济于事。 我得到每个Operation的DoWork()方法的4-5次迭代,然后一切都退了下来。
编辑我忘了澄清:我运行的每个操作都是从基本操作继承的。我:
public class TestLongOperation : Operation
{
public TestLongOperation(double secondsInterval) : base(secondsInterval) { }
public override void Work(object buh)
{
for (Int16 i = 0; i < Int16.MaxValue; i++)
{
for (short j = 0; j < short.MaxValue; j++)
{ }
}
}
}
有什么建议吗?如果上述内容不足,我可以提供更多代码。 提前谢谢。
答案 0 :(得分:1)
我有一种感觉,计时器在每个tick事件上创建一个新线程,我的服务有问题导致很多线程被生成,如果在下一个tick开始时仍有大量处理从前一个tick开始
我最终完全删除了计时器并用循环替换了它。然后在我的主处理线程中添加了一个Thread.sleep。然后它就像一个计时器,但不保持产生线程。此外,在处理完成之前,循环不会完成。
例如:
(主要的Thead)
bool running = true;
while (running)
{
//do processing
/sleep for 'timer' interval
Thread.Sleep(interval)
}
这有帮助吗?
答案 1 :(得分:0)
一些随意的想法:
当程序挂起时,如果你在几条“锁定”线上,你是否会遇到休息和cheeck。
这些是一次性定时器吗?如果是这样,在启用计时器之前连接了事件处理程序。如果没有,你的工作是否可以重入?
在计时器处理程序中,为什么要生成另一个线程来完成工作?计时器已将其置于新线程中。也许你遇到线程池耗尽?如果几个timerhandler启动并耗尽线程池,那么它们将等待启动工作线程。
阅读Timer.SynchronizingObject Property 以查看Timer可以使用ThreadPool。