处置后监控多个 Threading.Timers
我有一个进程,它创建一个动态计时器列表(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 中的一项直接任务。在我的简单单元测试中,我的 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; }
}
_
I have a process, which creates a dynamic list of timers(System.Threading.Timer) and continues to run until a signal is received to terminate. Once a signal is received to terminate I want any existing timer callbacks to complete (See Below):
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());
}
This code works right now, but I would like to monitor the ongoing thread callbacks once the timers are disposed. My intent is to write to a log at a given interval "Timer A is still running".
I started playing with:
ThreadPool.RegisterWaitForSingleObject(....)
add added the following:
(Note:I created a class ThreadContext which contains the timer and associated data)
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());
}
I feel like this should be a straight forward task in C# .net 4.0. In my simple unit test, My IsRunning callback fires quite a bit after the wait. I do not perform any further execution after this call. but I am writing quite a bit of code that I am not too comfortable with and feel like this will fail.
Is there a simpler solution or I am misunderstanding something?
UPDATE
Based on Peter R. suggestion I came up with the following below. Granted its more lines of code but I don't have to register a single thread object. If all the threads are still executing after disposal I sleep for 10 seconds and check again for this example.
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; }
}
_
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
如果您的处理程序尚未完成,您的 ManualResetEvents 将不会收到信号。因此,您可以简单地测试事件是否处于有信号状态。 IE
If your handlers haven't completed, your ManualResetEvents will not be signalled. So, you could simply test if the event is in a signaled state or not. i.e.