监控多线程.处置后的计时器
本文关键字:计时器 多线程 监控 | 更新日期: 2023-09-27 18:00:28
我有一个进程,它创建了一个定时器的动态列表(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(....)
add添加了以下内容:(注意:我创建了一个类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中的一项直接任务。在我的简单单元测试中,我的IsRunning回调在等待之后会触发一段时间。在这个调用之后,我不执行任何进一步的执行。但我正在写很多我不太适应的代码,我觉得这会失败。
有没有更简单的解决方案,或者我误解了什么?
更新根据Peter R.的建议,我提出了以下建议。允许它有更多的代码行,但我不必注册一个线程对象。如果所有线程在处理后仍在执行,我将睡眠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; }
}
_
如果处理程序尚未完成,则不会向ManualResetEvents发出信号。因此,您可以简单地测试事件是否处于信号状态。即
var isComplete = waiters[0].WaitOne(0);