2014-10-16 3 views
1

В C# Я пытаюсь создать службу Windows с двумя циклами, которые будут выполняться одновременно с установленными интервалами. Например, LoopA будет запускаться каждые 30 секунд и LoopB каждые 5 секунд.Параллельные циклы, выполняющиеся с различными интервалами

Задачи, которые будут выполняться внутри LoopA, могут занять более 30 secodns. Если это произойдет, LoopA начнет снова сразу, где, как если бы задача заняла только 20 секунд, LoopA не будет работать снова в течение 10 секунд.

Я уже реализовал LoopA. Моя проблема теперь заключается в том, что LoopB выполняет параллельную работу, ведя себя так же, как LoopA, за исключением 5-секундного интервала. Вот мой LoopA код, который проходит внутри Тема:

private Thread Worker; 
private AutoResetEvent StopRequest; 

private TimeSpan loop_a_freq; 
private TimeSpan loob_b_freq; 

public LoopManager(Thread _worker, AutoResetEvent _stopRequest) 
{ 
    // Threads 
    this.Worker = _worker; 
    this.StopRequest = _stopRequest; 

    RunLoopA(); 
} 

private void RunLoopA() 
{ 
    DateTime start_current_loop = DateTime.Now; 
    DateTime next_loop = start_current_loop + loop_a_freq; 

    for (;;) 
    { 
     // Do processing here 
     new LoopAction(); 

     DateTime now = DateTime.Now; 
     if (now > next_loop) 
     { 
      next_loop = now; 
     } 

     TimeSpan delay = next_loop - now; 
     Thread.Sleep(delay); 

     next_loop += loop_a_freq; 

     if (StopRequest.WaitOne(0)) 
     { 
      return; 
     } 
    } 
} 

Как я могу идти о реализации RunLoopB()? Темы - это один из аспектов C#, который я никогда не изучал полностью. Нужно ли использовать Parallel.For()?

+0

У вас есть возможность использовать «Таймер» для планирования ваших задач. Вы можете запускать потоки с заданными интервалами вместо бесконечного цикла, который спит. –

+0

Я сделал, но возникла проблема с тем, что таймер не мог правильно обрабатывать задачи, которые превышают интервал времени (так что если задача 30s фактически заняла 40 секунд). С тех пор моя спецификация дизайна изменилась, поэтому стоит заглянуть в нее. –

+0

Таймер будет запускать новый поток каждый заданный интервал, даже если предыдущий поток еще не закончен. Однако нет ничего, чтобы остановить вас, проверяя переменную в начале задачи «работа», чтобы увидеть, есть ли уже работающая задача, а затем просто возвращается, ничего не делая, если она есть. –

ответ

2

Вот небольшой фрагмент, который вы можете поместить в linqpad и протестировать. Это предотвратит перекрытие таймера. В основном мы выполняем обратный вызов, останавливаем таймер, обрабатываем некоторые работы, перезагружаем таймер и запускаем его снова. Вам понадобится таймер для каждой из ваших заданных по времени задач.

Чтобы быть ясным, это предотвратит бесполезное выполнение ваших потоков, поскольку вы создаете новый поток для обработки работы после завершения другого. Наличие 2 таймеров позволит вам запускать 2 разных процесса с разными интервалами, создавая собственные потоки. Опять же, разрешая только один экземпляр каждого процесса для каждого таймера.

Основной процесс

  1. установки таймера, без интервала в конструкторе
  2. Start Timer
  3. Таймер ждет тогда, когда истечет его запустить процесс на новом потоке
  4. Процесс останавливается таймер
  5. Процесс не работает
  6. Интервалы технологических установок для сброса таймера (Из-за "AutoReset" собственность)
  7. Процесс начинается таймер
  8. повторите процедуру с шага 3

Basic Code

private System.Timers.Timer _timer; 
private int _delaySeconds = 5; 

void Main() 
{ 
    // timer prevents threads from overlapping modify with care 
    _timer = new System.Timers.Timer(); 
    _timer.Interval = _delaySeconds*1000; 
    _timer.AutoReset = true;  // important to prevent overlap 
    _timer.Elapsed += OnProcess; 

    _timer.Start(); 
} 

private void OnProcess(object sender, System.Timers.ElapsedEventArgs args) 
{ 
    // timer prevents from thread overlapping modify with care 
    _timer.Stop(); 

    // do work 
    Debug.WriteLine("Processing on thread. [{0}]", Thread.CurrentThread.ManagedThreadId).Dump("this"); 

    // setting the interval resets the timer 
    _timer.Interval = _delaySeconds*1000; 
    _timer.Start(); 
} 

Устранение Производительность

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

http://msdn.microsoft.com/en-us/library/ee329530.aspx

+0

Thnaks очень много. Не могли бы вы кратко рассказать о том, что вы подразумеваете под «перекрытием потоков»? Если два таймера работают бок о бок, как будет «перекрываться»? –

+0

Несомненно, вы будете запускать оба ваших таймера параллельно, откручивая собственные потоки, чтобы часть работала нормально. Эта настройка предотвращает выполнение процесса ProcessA еще во время обработки. Он делает это, потому что ProcessA останавливает таймер, выполняет работу, а затем снова запускает таймер. Таким образом, в основном ProcessA будет иметь только один экземпляр этого процесса одновременно. Другими словами, ProcessA и ProcessB могут работать, но только один экземпляр одного из них с указанной выше настройкой. Если это не ясно, я могу перефразировать. – Tony

+0

Ты босс, Тони. Спасибо за помощь. –

1

Это, кажется, почти полностью готов к работе, но для того, чтобы получить другую нить работает, вы хотите, чтобы начать первую нить параллельно, то же самое для второго, и ожидание они оба.Это может быть проще, используя Tasks вместо Threads, но здесь он использует Thread s

public LoopManager(Thread _worker, AutoResetEvent _stopRequest) 
    { 
     // Threads 
     this.Worker = _worker; 
     this.StopRequest = _stopRequest; 

     var threadA = new Thread(RunLoopA); 
     var threadB = new Thread(RunLoopB); 

     // Start the loops 
     threadA.Start(); 
     threadB.Start(); 

     // Join the threads to avoid the program exiting before they're done 
     threadA.Join(); 
     threadB.Join(); 
    } 

    private void RunLoopB() {...} // As RunLoopA, but using the loop_b_freq variable 

Теперь, если вы хотите, чтобы быть в состоянии гарантировать, что каждый цикл стартует, не дожидаясь предыдущего завершения процесса, вы начиная смотреть на реализацию лучше обслуживается System.Timers.Timer class. Имейте в виду, что есть System.Threading.Timer, что вы не хотите использовать в этой ситуации, потому что ему не хватает шаблонов событий.

+0

Спасибо за ответ. Если бы я мог нажать «принять» на более чем один ответ, я бы это сделал! –

2
 using System.Timers; 

     enum EventType {quit, task}; 

     class LoopDaLoop { 

      Timer _30Seconds_publiser = new Timer(20000); 
      Timer _5Seconds_publisher = new Timer(5000); 

      Timer _terminator = new Timer(60000); 

      BlockingCollection<EventType> loopAEvents = new BlockingCollection<EventType>(); 
      BlockingCollection<EventType> loopBEvents = new BlockingCollection<EventType>(); 

      public LoopDaLoop() { 
       _30Seconds_publiser.Elapsed += _30Seconds_publiser_Elapsed; 
       _5Seconds_publisher.Elapsed += _5Seconds_publisher_Elapsed; 
       _terminator.Elapsed += _terminator_Elapsed; 
       _30Seconds_publiser.Start(); 
       _5Seconds_publisher.Start(); 
       _terminator.Start(); 

       Task.Run(() => loopA()); 
       Task.Run(() => loopB()); 
      } 

      void _terminator_Elapsed(object sender, ElapsedEventArgs e) { 
       loopAEvents.Add(EventType.quit); 
       loopBEvents.Add(EventType.quit); 
      } 

      void _5Seconds_publisher_Elapsed(object sender, ElapsedEventArgs e) { 
       loopBEvents.Add(EventType.task); 
      } 

      void _30Seconds_publiser_Elapsed(object sender, ElapsedEventArgs e) { 
       loopAEvents.Add(EventType.task); 
      } 


      private void loopA() { 
       while (loopAEvents.Take() != EventType.quit) { 
        // decrypt wife's personal email 
       } 
      } 

      private void loopB() { 
       while (loopBEvents.Take() != EventType.quit) { 
        // navigate attack drones 
       } 
      } 
     } 
Смежные вопросы