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

标签 c# .net multithreading

我知道 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/

相关文章:

c# - IIS/.Net 只允许对给定用户 session 的单个并发响应

c# - 如何让 ClosedXML 在公式中使用条件格式?

c# - AvalonEdit:级联高亮着色器

java - for循环JFrame图像替换

c# - 什么时候需要在 Entity Framework 中包含相关实体?

c# - 将控制台应用程序屏幕保存在 .txt 文件中

c++ - 当一个线程 forks() 时其他线程会发生什么?

c++ - Visual C++ 如何用线程启动非 void 函数

c# - 从ftp下载文件时如何设置进度条

c# - 动态创建 C# 类的实例