Является ли Thread.Sleep правильным способом для реализации моего собственного таймера в C #?

2

Я знаю, что 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 вместо повторного создания его снова и снова)

Это правильный способ сделать это? (В реальном приложении действие "Запуск" проверяет веб-службу, поэтому у меня нет способа оповестить мой поток, чтобы он проснулся раньше)

Или я должен использовать какую-то другую концепцию для создания потока? Одна из проблем, которую я вижу, - это реализация Stop. Run Thread запускает цикл, каждый раз проверяющий bool, но если я вызываю Stop(), мне нужно подождать, пока интервал сна не закончится, что неудобно.

Thread.Abort будет суровым, поэтому я думаю, что Thread.Interrupt будет работать как-то? Метод Stop() должен позволить Run завершить его текущую итерацию, чтобы не было жесткого прерывания. AutoResetEvent немного похож на то, что мне может понадобиться, но я не совсем понимаю, что он делает.

Изменить:. Один из способов, который я видел, это добавить таймер (так что отдельный поток), а затем запустить() конец не с помощью Thread.Sleep, а с некоторыми "Подождите, пока какой-нибудь объект изменения". Затем я изменил бы этот объект либо со второго потока (когда истечет 5 минут), либо из действия "Стоп". Но это кажется чрезмерным? По сути, Run должен реагировать на два условия: 5 минут истекает или какой-то внешний сигнал (например, изменение флага _exit). Что-то говорит мне, что должно быть что-то встроенное, но, возможно, еще одна тема Timer Thread была сосредоточена исключительно на отправке сигнала каждые 5 минут - это путь?

  • 1
    Можете ли вы перефразировать то, что вы хотите в предложении или два в конце вашей статьи? Ваш заголовок предполагает, что вам нужен таймер (который в мире C # является чем-то, чтобы измерить, сколько времени занимает что-то), но я подозреваю, что вы пришли из мира VB, где таймер означает что-то, что просыпается и запускает событие?
  • 0
    В этом смысле нет никакой разницы между VB и C #: таймер (System.Threading.Timer) активируется и запускает событие, секундомер (System.Diagnostics.Stopwatch) измеряет, сколько времени занимает что-то. Я хочу первое.
Показать ещё 1 комментарий
Теги:
multithreading

6 ответов

4
Лучший ответ

Если вас заставляют опросить, вам придется опросить. Thread.Sleep() подходит для этого.

Однако в отношении вас есть проблемы с прерываниями...

Я немного переписал решение для использования Monitor. Подождите/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 currently Wait'ing
}
  • 0
    Как это примерно работает? Мне в основном нужно изменить Run (), чтобы сделать что-то другое, если поступит какой-то внешний «сигнал» или пока не истечет 5 минут. Смотрите мое редактирование.
  • 0
    Смотрите редактировать. Надеюсь, это достаточно ясно.
Показать ещё 4 комментария
1

Да, это круто, вы также можете вызвать Thread.Interrupt(), чтобы прервать сон, а не ждать, пока сон вернется нормально.

в случае, если поток не блокируется при его прерывании, он будет продолжать обрабатывать нормально, пока он не попытается снова заснуть.

1

Есть ли причина, по которой вы не могли бы использовать таймер внутри потока? Вы получите то, что хотите, поток, который остается в живых навсегда, когда вы стреляете в ваш метод, а также можете просто остановить таймер в любой момент, не дожидаясь 5 минут или прерывая потоки?

(Я не очень опытен в потоковом режиме, поэтому я мог бы пропустить что-то очевидное?)

  • 0
    Не совсем, я просто «чувствую», что вращение вторичной нити является чрезмерным, но я тоже не испытываю.
  • 0
    Недостатком этого является то, что он использует другой поток из ThreadPool.
1

Если интервал времени имеет решающее значение, то предпочитают таймеры NOFOLLOW noreferrer высокого разрешения предусмотрено в окнах, которые будут запускать с более высокой точностью.

  • 0
    Благодарю. Нет, в этом случае это неважно, если это займет несколько миллисекунд (или даже секунд) больше или меньше.
0

Кажется хорошим решением для меня. Если вы беспокоитесь о том, чтобы остановить раньше, вы можете установить время сна меньше и сохранить счет, чтобы вы запускали фактический код каждые 5 минут. Таким образом, он чаще проверяет логическое значение и может вырваться раньше.

  • 0
    Это звучит довольно глупо, хотя, если честно: / это не так плохо, как создание SpinLock, но что-то подсказывает мне, что должна быть лучшая реализация.
0

Вы можете заглянуть в System.Timers.Timer, хотя правдиво просто спать не плохое решение.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню