Остановка таймера в его методе обратного вызова

Я обычно - сторонник помещения всего в хранимых процедурах по всем причинам, на которых DBAs были harping в течение многих лет. В случае Linq это верно, что не будет никакого различия в производительности с простыми запросами CRUD.

, Но имеют в виду несколько вещей при принятии этого решения: использование любого ORM связывает Вас плотно с Вашей моделью данных. DBA не имеет никакой свободы внести изменения в модель данных, не вынуждая Вас изменить Ваш скомпилированный код. С хранимыми процедурами можно скрыть эти виды изменений до степени, так как список параметров и набор (наборы) результатов, возвращенный из процедуры, представляют свой контракт, и внутренности могут переехаться, настолько долго поскольку тот контракт все еще выполняется.

И также, если Linq используется для более сложных запросов, настраивая базу данных, становится намного более трудной задачей. Когда хранимая процедура отстает, DBA может полностью сфокусироваться на коде в изоляции и имеет много опций, именно так тот контракт все еще удовлетворен, когда он сделан.

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

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

16
задан Kornelije Petak 9 November 2009 в 07:31
поделиться

3 ответа

Вы можете позволить таймер продолжит запускать метод обратного вызова, но оберните нереентерабельный код в Monitor.TryEnter / Exit. В этом случае нет необходимости останавливать / перезапускать таймер; перекрывающиеся вызовы не будут получать блокировку и немедленно возвращаться.

 private void CreatorLoop(object state) 
 {
   if (Monitor.TryEnter(lockObject))
   {
     try
     {
       // Work here
     }
     finally
     {
       Monitor.Exit(lockObject);
     }
   }
 }
46
ответ дан 30 November 2019 в 15:35
поделиться

Пара возможных решений:

  • реальная работа выполняется в еще одном делегате потока, который ожидает события. Обратный вызов таймера просто сигнализирует о событии. В рабочий поток нельзя повторно войти, так как он ' это единственный поток, который выполняет свою работу только при получении сигнала о событии. Таймер является реентерабельным, поскольку все, что он делает, это сигнализирует о событии (кажется немного окольным и расточительным, но он будет работать)
  • создайте таймер только с тайм-аутом запуска и без периодического тайм-аута, поэтому он сработает только один раз . Обратный вызов таймера удалит этот объект таймера и создаст новый, когда он завершит свою работу, который также сработает только один раз.

Вы можете управлять вариантом №2 без удаления / создания нового объекта, используя метод Change () исходного объекта таймера, но я не уверен, каково именно поведение вызов Change () с новым тайм-аутом начала после истечения первого тайм-аута. Это стоило бы одного или двух тестов.

Изменить:


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

private Timer _creatorTimer;

// BackgroundWorker's work
private void CreatorWork(object sender, EventArgs e) {
    // note: there's only a start timeout, and no repeat timeout
    //   so this will fire only once
    _creatorTimer = new Timer(CreatorLoop, null, 1000, Timeout.Infinite);

    // some other code that worker is doing while the timer is active
    // ...
    // ...
}

private void CreatorLoop(object state) {
    Console.WriteLine( "In CreatorLoop...");
    /*
        ... Work here
    */
    Thread.Sleep( 3000);

    // Reenable timer
    Console.WriteLine( "Exiting...");

    // now we reset the timer's start time, so it'll fire again
    //   there's no chance of reentrancy, except for actually
    //   exiting the method (and there's no danger even if that
    //   happens because it's safe at this point).
    _creatorTimer.Change(1000, Timeout.Infinite);
}
6
ответ дан 30 November 2019 в 15:35
поделиться

У меня была аналогичная ситуация с System.Timers.Timer, где прошедшее событие выполняется из пула потоков и требует повторного входа.

Я использовал этот метод, чтобы обойти проблема:

private void tmr_Elapsed(object sender, EventArgs e)
{
    tmr.Enabled = false;
    // Do Stuff
    tmr.Enabled = true;
}

В зависимости от того, что вы делаете, вы можете рассмотреть System.Timers.Timer, вот хорошее резюме из MSDN

                                         System.Windows.Forms    System.Timers         System.Threading  
Timer event runs on what thread?         UI thread               UI or worker thread   Worker thread
Instances are thread safe?               No                      Yes                   No
Familiar/intuitive object model?         Yes                     Yes                   No
Requires Windows Forms?                  Yes                     No                    No
Metronome-quality beat?                  No                      Yes*                  Yes*
Timer event supports state object?       No                      No                    Yes
Initial timer event can be scheduled?    No                      No                    Yes
Class supports inheritance?              Yes                     Yes                   No

* Depending on the availability of system resources (for example, worker threads)            
0
ответ дан 30 November 2019 в 15:35
поделиться
Другие вопросы по тегам:

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