代码之家  ›  专栏  ›  技术社区  ›  Spencer Ruport

线程睡眠和Windows服务

  •  7
  • Spencer Ruport  · 技术社区  · 14 年前

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

    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)我在这里走对了吗?这比用更好吗 线程() ?

    2 回复  |  直到 14 年前
        1
  •  19
  •   Aaronaught    14 年前

    老实说,我不得不说,我觉得你在这里有点不太习惯。

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

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

    假设您需要每隔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();
    }
    

    只有当您需要在服务中开始创建工作线程时,工作本身才能运行很长时间,并且您需要能够在中间取消。这往往涉及大量的设计工作,所以我不会在不确定它是否与您的场景相关的情况下进入到这一点。

    最好不要在服务中引入多线程语义,除非您确实需要它。如果你只是想安排一些小的工作单元去完成,你肯定不需要它。

        2
  •  1
  •   Timores    14 年前

    我最近写了一个服务,需要做一些工作,然后等待N分钟,然后循环。

    我还使用了manualResetevent(称为Evt)和onStop中的set()调用。 但我不需要计时器。

    在服务线程中,我有:

    for (;;) {
    
       // do some work
       if (_evt.WaitOne(_waitInterval)) {
    
           // got the signal => time to leave
           break;
       }
    }
    

    因此,可能发生了超时=>需要更多工作的时间。调用或set()并终止循环。