@PickGG

Как сделать чтобы таймер мог выполнять долгую работу?

Есть код.
// Создаем таймер из System.Threading
Timer timer = new Timer(OnTimer, state: null, dueTime: 0, period: 1000);

static void OnTimer(object state)
{
        Thread.Sleep(5000); // Симуляция работы
}

Проблема вот в чем.
Работа идет 5 секунд. Интервал таймера 1 секунда. В итоге за 1 секунду одновременно запустится 5 работ, которые будут выполняться одновременно. Я бы хотел чтобы таймер не запускал новую пока старая не завершится.

Придумал вот такое решение с помощью System.Timers.Timer.
// Создаем таймер
timer = new System.Timers.Timer(1000);
timer.Elapsed += Timer_Elapsed;
timer.Start();

private static void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
            timer.Stop(); // Останавливаем таймер чтобы он не вызвался второй раз через секунду.
            Thread.Sleep(5000); // Симуляция работы
            timer.Start();
}

Как видно это решение говнокод по двум причинам:
1. System.Timers.Timer это компонент Windows Forms, а я пишу фреймворк. Некрасиво получается.
2. Перед каждым return приходится запускать таймер а также внутри каждого catch.
Подскажите правильное решение.
  • Вопрос задан
  • 375 просмотров
Решения вопроса 2
sarapinit
@sarapinit Куратор тега C#
Точу водой камень
Я использую такое решение, таймер ждет пока работа не закончится. На самом деле я просто выключаю его пока работа выполняется, а после завершения или исключения запускаю снова.

public class TestWorker
{
  private readonly Timer _timer;
  public TestWorker()   
  {
    _timer = new Timer(
      Callback, 
      null, 
      TimeSpan.FromSeconds(1),          
      TimeSpan.Zero);
  }

  private void Callback(object state)
  {
    try
    {
      //work imitation
      Thread.Sleep(5000);
    }
    finally
    {
      _timer.Change(
        TimeSpan.FromSeconds(1),    
        TimeSpan.Zero);
    }
  }
}
Ответ написан
@PickGG Автор вопроса
Изобрел свой таймер
public class WorkTimer : Disposable
    {
        private readonly System.Threading.Timer timer;
        private readonly TimerCallback timerCallback;
        private int interval;
        private bool timerIsCalling = false;

        public WorkTimer(TimerCallback callback, object state, int dueTime, int interval)
        {
            timerCallback = callback;
            Interval = interval;

            timer = new System.Threading.Timer(Callback, state, dueTime, Interval);
        }

        protected override void ReleaseUnmanagedResources()
        {
            timer?.Dispose();
        }

        public int Interval
        {
            get { OnCallAnyMethod(); return interval; }
            set {
                OnCallAnyMethod();

                interval = value;
                if (!timerIsCalling)
                    timer?.Change(value, value);
            }
        }

        private void Callback(object state)
        {
            timerIsCalling = true;
            timer.Change(-1, -1); // Stop timer
            this.timerCallback(state);
            timer.Change(Interval, Interval); // Resume timer
            timerIsCalling = false;
        }

    }
Ответ написан
Комментировать
Пригласить эксперта
Ответы на вопрос 1
freeExec
@freeExec
Участник OpenStreetMap
Так вы разделите таймер и полезная нагрузка. А в таймере проверяете, если старая ещё работает, то новую не запускаете.
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы