У меня есть процесс, который создает динамический список таймеров (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; }
}
_