我知道 System.Threading.Timer 存在,但我已经有一个线程。该线程应该一直保持事件状态,但仅每 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 而不是一遍又一遍地重新创建它)
这是正确的做法吗? (在真实的应用程序中,运行操作检查 Web 服务,所以我无法通知我的线程提前唤醒)
或者我应该使用其他一些概念来拥有线程吗?我看到的一个问题是 Stop 的实现。 Run Thread 运行一个循环,每次检查一个 bool 值,但如果我调用 Stop(),我必须等到 sleep 间隔结束,这很不方便。
Thread.Abort 会很苛刻,所以我想 Thread.Interrupt 会以某种方式起作用吗? Stop() 方法应该允许 Run 完成它的当前迭代,所以没有硬中止。 AutoResetEvent 看起来有点像我可能需要的,但我不完全理解它的作用。
编辑:我认为这可能的一种方法是添加一个计时器(因此是一个单独的线程),然后让 Run() 结束而不是 Thread.Sleep,而是以一些“等到某个对象变化”。然后,我将从第二个线程(5 分钟到期时)或停止操作更改该对象。但这似乎过分了?本质上,Run 需要对两种情况使用react:5 分钟到期或一些外部信号(如 _exit 标志的更改)。有些东西告诉我应该有一些内置的东西,但也许有另一个定时器线程只专注于每 5 分钟发送一个信号是可行的方法吗?
最佳答案
如果你被迫投票,那么你就被迫投票。 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
}
关于c# - Thread.Sleep 是在 C# 中实现我自己的 Timer 的正确方法吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2032540/