简体   繁体   English

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

[英]Is Thread.Sleep the proper way to implement my own Timer in C#?

I am aware that System.Threading.Timer exists, but I already have a Thread. 我知道System.Threading.Timer存在,但是我已经有一个线程。 This thread is supposed to stay alive all the time, but only execute every X seconds. 该线程应该一直保持活动状态,但仅每X秒执行一次。 The test implementation looks like this: 测试实现如下所示:

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;
    }
}

The Run method executes, then sleeps for 5 Minutes, then executes again. Run方法将执行,然后睡眠5分钟,然后再次执行。 So it's basically a timer that fires every 5 Minutes + the time it takes to execute the action. 因此,基本上,这是一个计时器,每5分钟触发一次+执行该操作所需的时间。 (and yes, I should cache the TimeSpan instead of re-creating it over and over) (是的,我应该缓存TimeSpan,而不是一遍又一遍地重新创建它)

Is this the proper way to do it? 这是正确的方法吗? (In the real app, the Run action checks a Web Service, so I have no way to signal my Thread to wake up earlier) (在真实的应用程序中,“运行”操作会检查Web服务,因此我无法发信号通知我的线程更早唤醒)

Or should I use some other concept to have the thread? 还是应该使用其他概念来创建线程? One problem I see is the implementation of Stop. 我看到的一个问题是Stop的实现。 The Run Thread runs a loop that checks a bool every time, but if I call Stop() I have to wait until the Sleep Interval is over, which is inconvenient. 运行线程运行一个循环,每次都会检查一次布尔值,但是如果我调用Stop(),则必须等到睡眠间隔结束,这很不方便。

Thread.Abort would be harsh, so I guess Thread.Interrupt would work somehow? Thread.Abort会很苛刻,所以我猜Thread.Interrupt会以某种方式工作? The Stop() Method should allow Run to finish it's current iteration, so no hard abort. Stop()方法应允许Run完成其当前迭​​代,因此不会硬终止。 AutoResetEvent looks a bit like what I could need, but I don't fully understand what it does. AutoResetEvent看起来有点像我需要的东西,但是我不完全了解它的作用。

Edit: One way I would see this possible is to add a Timer (so a separate thread) and then have Run() end not with Thread.Sleep but with some "Wait until some object changes". 编辑:我认为这可能的一种方法是添加一个Timer(这样一个单独的线程),然后让Run()不以Thread.Sleep结尾,而是以“等待直到某些对象更改”结束。 I would then change that object either from the second Thread (when the 5 minutes expire) or from the Stop action. 然后,我将从第二个线程(5分钟后到期)或从“停止”操作更改该对象。 But that seems excessive? 但这似乎过度吗? Essentially, Run needs to react to two conditions: 5 Minutes expire or some external signal (like the change of the _exit flag). 本质上,运行需要对以下两种情况作出反应:5分钟到期某些外部信号(例如_exit标志的更改)。 Something tells me there should be something built-in, but maybe having another Timer Thread solely focused on sending a signal every 5 minutes is the way to go? 有人告诉我应该内置一些东西,但是也许有另一个Timer Thread专门专注于每5分钟发送一次信号,这是可行的方法吗?

If you're forced to poll, then you're forced to poll. 如果您被迫轮询,那么您将被迫轮询。 Thread.Sleep() is fine for that. Thread.Sleep()很好。

However with regards to you're interrupt concerns... 但是,关于您的干扰令人担忧...

I'd re-write your solution a bit to use Monitor. 我会稍微重写您的解决方案以使用Monitor。 Wait / Pulse . 等待 / 脉冲 That does require you keep an object around solely to lock(...){} on it, but it strikes me as a cleaner solution. 确实需要您仅保留一个对象以将其lock(...){} ,但这使我感到更干净。

I say cleaner because using Thread.Interrupt() is effectively using exceptions for "normal" control flow. 我说比较干净,因为使用Thread.Interrupt()有效地将异常用于“常规”控制流。 Stopping a Timer is in no way unexpected. 停止计时器绝非意外。 But its a design smell really (if such things exist), nothing more. 但是它确实具有设计气味(如果存在此类气味),仅此而已。

Quicky outline: 快速概述:

//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
}

yeah that's cool, you can also call Thread.Interrupt() to interrupt the sleep, rather than waiting for sleep to return normally. 是的,这很酷,您还可以调用Thread.Interrupt()来中断睡眠,而不是等待睡眠正常返回。

in the case the thread is not blocking when you interrupt it, it will continue processing normally until it tries to sleep again. 如果线程在中断时没有阻塞,它将继续正常处理,直到尝试再次进入睡眠状态为止。

Is there a reason you couldn't just use a timer inside the thread? 您有不能仅仅在线程使用计时器的原因吗? You'd get what you want, a thread that stays alive forever while firing off your method, plus you could just stop the timer at any point without waiting for 5 minutes or interrupting threads? 您会得到想要的东西,一个线程在触发您的方法时可以永远存活,而且您可以随时停止计时器而无需等待5分钟或中断线程?

(I'm not very experienced in threading, so I might be missing something obvious?) (我在线程方面的经验不是很丰富,所以我可能缺少明显的东西吗?)

如果时间间隔很关键,则最好使用窗口中提供的高分辨率计时器 ,以更高的精度触发。

Seems like a good solution to me. 对我来说似乎是一个很好的解决方案。 If you're worried about stopping sooner, you can set the sleep time to be less and keep a count so you only run the actual code every 5 minutes. 如果您担心过早停止,可以将睡眠时间设置为较短并保持计数,以便仅每5分钟运行一次实际代码。 That way it's checking the boolean more often and can break out sooner. 这样,它会更频繁地检查布尔值,并且可以更快地爆发。

您也可以查看System.Timers.Timer ,尽管说实话,睡觉并不是一个不错的解决方案。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM