Используя блокировку с Поточной обработкой. Таймер

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

14
задан James 8 November 2009 в 23:48
поделиться

2 ответа

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

static Timer timer;

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, Timeout.Infinite);
}

public void DoSomething()
{
      try
      {
           // my processing code
      }
      finally
      {
          timer.Change(10000, Timeout.Infinite);
      }
}

Этот код сообщает вновь созданному таймеру немедленно срабатывать, только один раз. В коде обработки он выполняет свою работу, а затем сообщает таймеру, чтобы он сработал снова через 10 секунд, только один раз. Поскольку таймер теперь не срабатывает периодически, а перезапускается его методом обратного вызова, обратный вызов гарантированно будет однопоточным без очереди.

Если вы хотите сохранить постоянный интервал, то это немного сложнее, чем вы должны решить, что делать, если обработка начинается дольше, чем интервал таймера. Один вариант - делать то, что ты » re, но это, по сути, приведет к большому количеству потоков в очереди и возможному истощению пула потоков. Другой вариант - просто отказаться от обратного вызова, если он уже выполняется, например

static Timer timer;
static object locker = new object();

public void Start()
{
    var callback = new TimerCallback(DoSomething);
    timer = new Timer(callback, null, 0, 10000);
}

public void DoSomething()
{
      if (Monitor.TryEnter(locker))
      {
           try
           {
               // my processing code
           }
           finally
           {
               Monitor.Exit(locker);
           }
      }
}
35
ответ дан 1 December 2019 в 07:19
поделиться

Худшее, что может случиться, если выполнение кода обработки занимает более 10 секунд, - это то, что вы будете тратить 1 поток пула потоков каждый раз, когда будет вызван новый обратный вызов (они будут ждать в блокировке заявление). И если вы возьмете все потоки пула потоков HttpWebRequest, ASP.NET, пострадают вызовы асинхронных делегатов ...

Я бы сразу запланировал первый обратный вызов. Затем, если вам действительно нужно, чтобы ваш DoSomething () вызывался каждые 10 секунд:

public void DoSomething ()
{
       DateTime start = DateTime.UtcNow;
       ...
       TimeSpan elapsed = (DateTime.UtcNow - start);
       int due_in = (int) (10000 - elapsed.TotalMilliseconds);
       if (due_in < 0)
           due_in = 0;
       timer.Change (due_in, Timeout.Infinite);
}

Или что-то в этом роде.

2
ответ дан 1 December 2019 в 07:19
поделиться
Другие вопросы по тегам:

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