Thread.Sleep是在C#中实现自己的Timer的正确方法吗?

时间:2010-01-09 06:18:09

标签: c# .net multithreading

我知道System.Threading.Timer存在,但我已经有了一个Thread。该线程应始终保持活动状态,但每隔X秒执行一次。测试实现如下所示:

public class MailClass
{
    private Action<string> LoggerAction;
    private bool _exit;

    public MailClass(Action<string> loggerAction)
    {
        LoggerAction = loggerAction;
    }

    public void Run()
    {
        LoggerAction("Run called");
        _exit = false;
        while(!_exit)
        {
            Thread.Sleep(TimeSpan.FromSeconds(300));
            LoggerAction("Waking up");
        }
        LoggerAction("Run ended");
    }

    public void Stop()
    {
        LoggerAction("Stop called");
        _exit = true;
    }
}

Run方法执行,然后休眠5分钟,然后再次执行。所以它基本上是一个计时器,每5分钟触发一次+执行动作所需的时间。 (是的,我应该缓存TimeSpan而不是一遍又一遍地重新创建它)

这是正确的方法吗? (在真实应用程序中,Run操作检查Web服务,因此我无法通知我的Thread早先唤醒)

或者我应该使用其他一些概念来获得该线程?我看到的一个问题是Stop的实现。运行线程运行一个循环,每次都检查一个bool,但如果我调用Stop(),我必须等到Sleep Interval结束,这很不方便。

Thread.Abort会很苛刻,所以我猜Thread.Interrupt会以某种方式工作吗? Stop()方法应该允许Run完成它的当前迭代,所以没有硬中止。 AutoResetEvent看起来有点像我需要的东西,但我不完全理解它的作用。

编辑:我认为这种可能的一种方法是添加一个Timer(所以一个单独的线程),然后让Run()结束不使用Thread.Sleep而是使用一些“等到某个对象变化”。然后我会从第二个Thread(5分钟到期时)或Stop操作更改该对象。但那似乎过分了?本质上,Run需要对两个条件做出反应:5分钟到期某些外部信号(如_exit标志的更改)。有些东西告诉我应该有内置的东西,但也许还有另一个定时器线程专注于每隔5分钟发送一个信号就可以了?

6 个答案:

答案 0 :(得分:4)

如果您被迫投票,那么您将被迫进行投票。 Thread.Sleep()就好了。

但是关于你的中断问题......

我会重新编写您的解决方案以使用Monitor。Wait / Pulse。这确实需要你只在lock(...){}上保留一个对象,但它让我感觉更清洁。

我说更干净,因为使用Thread.Interrupt()有效地使用“正常”控制流的异常。停止计时器绝不是意料之外的。但它的设计气味真的(如果存在这样的东西),仅此而已。

快速概述:

//Instead of Thread.Sleep(FIVE_MIN) in Run()...
lock(some_obj)
{
  if(Monitor.Wait(some_obj, FIVE_MIN))  //Wait for 5 min (or whatever) or until some_obj is Pulse'd
  {
    //Got Pulse
  }
  else
  {
    //Timeout expired
  }
}

//And in Stop()...
_exit = true;
lock(some_obj)
{
  Monitor.Pulse(some_obj);  //Wakeup the thread in Run() if it's currently Wait'ing
}

答案 1 :(得分:1)

是的,这很酷,你也可以打电话给Thread.Interrupt()来打断睡眠,而不是等待睡眠恢复正常。

如果线程在中断时没有阻塞,它将继续正常处理,直到它再次尝试进入休眠状态。

答案 2 :(得分:1)

是否有理由不能在线程中使用 计时器?你得到了你想要的东西,一个在启动你的方法时永远保持活力的线程,你还可以在任何时候停止计时器而不等待5分钟或中断线程?

(我在线程方面不是很有经验,所以我可能会遗漏一些明显的东西?)

答案 3 :(得分:1)

如果时间间隔很关键,那么请选择窗口中提供的high resolution timers,这样会更准确地触发。

答案 4 :(得分:0)

对我来说似乎是一个很好的解决方案。如果您担心提前停止,可以将睡眠时间设置为更少并保持计数,这样您每5分钟只运行一次实际代码。这样它可以更频繁地检查布尔值并且可以更快地发布。

答案 5 :(得分:0)

你也可以调查一下System.Timers.Timer,但真实地说睡觉并不是一个糟糕的解决方案。