线程睡眠和Windows服务

时间:2010-03-08 23:36:01

标签: .net multithreading windows-services timer sleep

我正在处理与Thread.Sleep()存在问题的Windows服务,所以我想我会尝试使用计时器,因为这个问题建议:

Using Thread.Sleep() in a Windows Service

我不清楚如何实现这一点。我相信这是方法,但我只想确保:

'' Inside The Service Object
Dim closingGate As System.Threading.AutoResetEvent

Protected Overrides Sub OnStart(ByVal args() As String)
   Dim worker As New Threading.Thread(AddressOf Work)
   worker.Start()
End Sub

Protected Sub Work()
   Dim Program = New MyProgram()
   closingGate = New System.Threading.AutoResetEvent(False)
   Program.RunService(closingGate)
End Sub

Protected Overrides Sub OnStop()
   closingGate.Set()
End Sub

'' Inside My Programs Code:
Public Sub RunService(closingGate As AutoResetEvent)
   Dim tmr As New Timer
   '' ...and so on

   closingGate.WaitOne()
End Sub

除了使用VB.Net(开玩笑,但如果可以的话,我会使用C#。)我是否在正确的轨道上?这比使用Thread.Sleep()更好吗?

2 个答案:

答案 0 :(得分:19)

老实说,我不得不说,我认为你在这里有点偏僻。

首先,发布的实际代码并没有多大意义;工作线程正在等待信号但是没有任何理由 - 它实际上并不是在任何类型的循环中或等待资源。其次,如果您确实需要在收到关闭信号后在worker中执行一些(可能省略的)清理代码,那么您的服务可能不会给工作线程足够的时间来清理。

但是,从根本上说,你所做的就是将问题转移到一个单独的线程中。这可能使服务对服务控制器保持响应,但它不能解决设计问题 - 并且通过使用线程和互斥体会增加许多不必要的复杂性;最终,如果你需要,它只会让你的服务更难调试。

假设您需要每5秒执行一些代码。这个想法是,不是“等待”5秒,而是反转控件,让计时器调用你的工作。

这很糟糕:

protected override void OnStart(string[] args)
{
    while (true)
    {
        RunScheduledTasks();    // This is your "work"
        Thread.Sleep(5000);
    }
}

这很好:

public class MyService : ServiceBase
{
    private Timer workTimer;    // System.Threading.Timer

    protected override void OnStart(string[] args)
    {
        workTimer = new Timer(new TimerCallback(DoWork), null, 5000, 5000);
        base.OnStart(args);
    }

    protected override void OnStop()
    {
        workTimer.Dispose();
        base.OnStop();
    }

    private void DoWork(object state)
    {
        RunScheduledTasks();  // Do some work
    }
}

就是这样。这就是你要定期工作的全部工作。只要工作本身一次不运行几秒钟,您的服务将保持对服务控制器的响应。在这种情况下,您甚至可以支持暂停:

protected override void OnPause()
{
    workTimer.Change(Timeout.Infinite, Timeout.Infinite);
    base.OnPause();
}

protected override void OnContinue()
{
    workTimer.Change(0, 5000);
    base.OnContinue();
}

您需要在服务中开始创建工作线程的唯一时间是工作本身可以运行很长时间,并且您需要能够在中间取消。这往往涉及大量的设计工作,所以如果不确定它与你的场景有关,我就不会深入研究。

除非您真的需要,否则最好不要开始在您的服务中引入多线程语义。如果您只是想安排小工作单元,那么您绝对不需要它。

答案 1 :(得分:1)

我最近写了一个必须做一些工作的服务,然后等了n分钟,然后循环。

我还使用了ManualResetEvent(名为_evt),并在OnStop中调用了Set()。 但我不需要计时器。

在服务主题中,我有:

for (;;) {

   // do some work
   if (_evt.WaitOne(_waitInterval)) {

       // got the signal => time to leave
       break;
   }
}

因此,发生超时=>一些更多工作的时间。或者调用Set()并终止循环。