2010-09-24 4 views
2

Я пытаюсь написать службу в C#, которая должна запускаться на заданный интервал (таймаут) с заданной даты. Если дата в будущем, служба должна ждать, пока она не будет достигнута.Синхронизация службы с таймером

Пример:

  • Если установить тайм-аут, чтобы быть 1 час от 21:00:00 Я хочу, чтобы запустить программу каждый час

  • Если установить тайм-аут, чтобы быть 1 час от 3999.01.01 21:00:00 Я хочу программу до до даты и с тех пор не запускать каждый час

Я вроде добился того, что с помощью следующего кода, но она имеет некоторые Prob лемы!

  1. Когда я установить службу (с InstallUtil) услуга помечается как начиная из-за 'Thread.Sleep()'. Эта служба, кажется, висит и «устанавливает» до начала.

  2. Код внутри 'ServiceTimer_Tick()' может занять больше времени, чем ожидалось. Как я могу предотвратить увеличение стека таймера, если это произойдет?

Альтернативы Я подумал:

  • включают с помощью «timeout.Interval» в первый раз, а затем сбросить его последующие вызовы, но он не чувствует себя хорошо.

  • Я также рассмотрел возможность отбросить всю идею обслуживания и скомпилировать ее как исполняемый файл и настроить запланированные задачи.

Укороченный пример:

public Service() 
{ 
    _timeout = new TimeSpan(0,1,0,0); 
    _timer = new System.Timers.Timer(); 
    _timer.Interval = _timeout.TotalMilliseconds; 
    _timer.Elapsed += new ElapsedEventHandler(ServiceTimer_Tick);    
} 

private void ServiceTimer_Tick(object sender, System.Timers.ElapsedEventArgs e) 
{    
    lock (_obj) 
    { 
     // Stuff that could take a lot of time 
    } 
} 

public static void Main() 
{ 
    Run(new Service()); 
} 

protected override void OnStart(string[] args) 
{ 
    long current = DateTime.Now.Ticks; 
    long start = new DateTime(2010,9,15,21,0,0).Ticks; 
    long timeout = _timeout.Ticks; 
    long sleep; 

    if (current > start) 
     sleep = timeout - ((current % timeout)) + (start % timeout); 
    else 
     sleep = start - current; 

    Thread.Sleep(new TimeSpan(sleep)); 

    _timer.AutoReset = true; 
    _timer.Enabled = true; 
    _timer.Start(); 
} 
+0

Я не очень понимаю, что вы привязывания достичь. Год 3999? Что делает тайм-аут? .... Это может быть связано: [Как генерировать событие в определенное время в C#?] (Http://stackoverflow.com/questions/1297109) – dtb

+0

Я просто установил дату/год, который, очевидно, был бы будущее - вместо этого это смутило вас и, возможно, многих других. – Makach

ответ

1

вам необходимо переместить таймерную логику в отдельный поток, который вы создаете из своей процедуры OnStart. Тогда ваша логика не может помешать работе SCM, и сервис начнется нормально.

Редактирование: просто для уточнения - для этой задачи я не думаю, что таймеры работают очень хорошо, поскольку вы не учитываете поправки часов, которые могут привести к перекосу (или даже быть неправильным, если пользователь вручную изменяет часы время). Вот почему сравнение с часовым временем с небольшими интервалами является предпочтительным.

Run рутина этого потока может выглядеть следующим образом:

public void run() 
    { 
     while (processing) 
     { 
      //initiate action on every full hour 
      if (DateTime.Now.Second == 0 && DateTime.Now.Minute == 0) 
      { 
       //Do something here 
       DoSomething(); 
       //Make sure we sleep long enough that datetime.now.second > 0 
       Thread.Sleep(1000); 
      } 
      Thread.Sleep(100); 
     } 
    } 
+0

Это окончательно перемещает меня в правильном направлении. Вы читаете мой вопрос :) – Makach

+0

Проверка каждые 100 миллисекунд, если полный час был достигнут, - это движение в неправильном направлении. Ожидание - это задание таймера. – dtb

+1

вы не можете просто ждать 5 часов и предположить, что часы не были скорректированы/отрегулированы в среднем, ведь в конце вы заинтересованы в часах, а не при истечении таймера. – BrokenGlass

2

Вы можете использовать System.Threading.Timer. Он поддерживает как dueTime, так и period, который является именно тем, что вам нужно.

2

Этого проще с помощью System.Threading.Timer. Вы можете сказать, как долго ждать до первого тика, а затем, как часто после этого гадать.

Итак, если вы хотите подождать 2 дня до начала, а затем сделать что-то один раз в час, вы бы написать:

Timer MyTimer = new Timer(TimerCallback, null, TimeSpan.FromHours(48), TimeSpan.FromHours(1)); 

, что сказал, если это то, что имеет только запустить один раз в час, то это звучит так, как вы действительно хотите, это исполняемый файл, который вы планируете с помощью планировщика заданий Windows.

Смежные вопросы