Мониторинг нескольких Threading.Timers после утилизации - PullRequest
2 голосов
/ 28 июня 2011

У меня есть процесс, который создает динамический список таймеров (System.Threading.Timer) и продолжает работать, пока не будет получен сигнал на завершение. После получения сигнала о завершении я хочу завершить все существующие обратные вызовы таймера (см. Ниже):

private IList<Timer> _timers = new List<Timer>();
...
...
private void WaitOnExecutingThreads()
{
  var waiters = new List<ManualResetEvent>(_timers.Count);

  foreach (var timer in _timers)
  {
      var onWait = new ManualResetEvent(false);
      waiters.Add(onWait);
      timer.Dispose(onWait);
  }

  WaitHandle.WaitAll(waiters.ToArray());
  waiters.ForEach(x=> x.Dispose());
}

Этот код работает прямо сейчас, но я бы хотел отслеживать текущие обратные вызовы потоков после удаления таймеров. Мое намерение состоит в том, чтобы записать в журнал с заданным интервалом «Таймер A все еще работает».

Я начал играть с:

ThreadPool.RegisterWaitForSingleObject(....)

добавить добавил следующее: (Примечание: я создал класс ThreadContext, который содержит таймер и связанные данные)

private void WaitOnExecutingThreads()
{
   var waiters = new List<ManualResetEvent>();

   WaitOrTimerCallback IsRunning = (x, timeout) => { if (timeout) { Log(x + "is still    running"); } };

   foreach (var threadContext in _threadContexts)
   {
      var onWait = new ManualResetEvent(false);
      threadContext.Timer.Dispose(onWait);

      ThreadPool.RegisterWaitForSingleObject(onWait, IsRunning , threadContext.ThreadInfo.Id, new TimeSpan(0, 0, 30), false);

      waiters.Add(onWait);
   }

        WaitHandle.WaitAll(waiters.ToArray());
        waiters.ForEach(x=> x.Dispose());
    }

Я чувствую, что это должно быть простой задачей в C # .net 4.0. В моем простом модульном тесте обратный вызов My IsRunning срабатывает довольно долго после ожидания. Я не выполняю дальнейшее выполнение после этого вызова. но я пишу довольно много кода, который мне не очень удобен, и я чувствую, что это потерпит неудачу.

Есть ли более простое решение или я что-то неправильно понимаю?

UPDATE Основываясь на предложении Питера Р., я придумал следующее. Конечно, он содержит больше строк кода, но мне не нужно регистрировать один объект потока. Если все потоки все еще выполняются после удаления, я сплю 10 секунд и снова проверяю этот пример.

    private void WaitOnExecutingThreads()
    {
        foreach (var threadContext in _threadContexts)
        {
            threadContext.DisposeWaiter = new ManualResetEvent(false);
            threadContext.Timer.Dispose(threadContext.DisposeWaiter);
        }

        while(_threadContexts.Count > 0)
        {
            for(var i = 0; i < _threadContexts.Count; i++)
            {
                var threadContext = _threadContexts[i];
                var isComplete = threadContext.DisposeWaiter.WaitOne(0);
                if(isComplete)
                {
                    Console.WriteLine(string.Format("{0}: {1} has completed", DateTime.Now, threadContext.Name));
                    _threadContexts.RemoveAt(i);
                }
                else
                {
                    Console.WriteLine(string.Format("{0}: {1} is still running", DateTime.Now, threadContext.Name));
                }
            }

            if (_threadContexts.Count > 0)
            {
                Thread.Sleep(new TimeSpan(0, 0, 10));
            }
        }
    }
....
public class ThreadContext
{
    public string Name { get; set; }
    public Timer Timer { get; set; }
    public WaitHandle DisposeWaiter { get; set; }
}

_

1 Ответ

0 голосов
/ 12 июля 2011

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

var isComplete = waiters[0].WaitOne(0);
...