我有一台List<System.Threading.Timer>。每个计时器以可配置的时间间隔(默认为10分钟)触发。它们都调用相同的回调方法(使用不同的参数)。回调方法可能需要几秒钟才能完成它的工作。
当程序终止时,回调方法的执行看起来会立即停止(我没看错吧?)
在退出程序之前,我如何优雅地等待当前正在执行的回调方法完成?
发布于 2012-01-30 18:26:23
你可以用WaitHandler参数来处理所有的定时器。此处理程序仅在回调方法完成时才会发出信号(正如spec所说:“计时器直到所有当前排队的回调都完成后才会被释放”)。
void WaitUntilCompleted(List<Timer> myTimers)
{
List<WaitHandle> waitHnd = new List<WaitHandle>();
foreach (var timer in myTimers)
{
WaitHandle h = new AutoResetEvent(false);
if(!timer.Dispose(h)) throw new Exception("Timer already disposed.");
waitHnd.Add(h);
}
WaitHandle.WaitAll(waitHnd.ToArray());
}编辑:@Peter在Dispose方法返回值的重要性下划线。当计时器已经被释放时,它返回false。为了确保这个解决方案保持可靠,我修改了它,当计时器已经释放时抛出异常,因为在这种情况下我们无法控制它的回调何时结束,尽管早期的释放回调可能仍然在运行!
发布于 2016-09-15 21:46:52
Tomek给出的公认答案很好,但并不完整。如果Dispose函数返回false,则意味着不需要等待完成,因为线程已经完成。如果您在这种情况下尝试等待WaitHandle,WaitAll将永远不会返回,因此您自己创建了一个函数来任意冻结您的应用程序/线程。
下面是它应该是什么样子:
void WaitUntilCompleted(List<Timer> myTimers)
{
List<WaitHandle> waitHnd = new List<WaitHandle>();
foreach (var timer in myTimers)
{
WaitHandle h = new AutoResetEvent(false);
if (timer.Dispose(h))
{
waitHnd.Add(h);
}
}
WaitHandle.WaitAll(waitHnd.ToArray());
}发布于 2012-01-30 17:48:39
您可以使用ManualResetEvents阻塞主线程,直到任何挂起的操作完成。
例如,如果您希望所有计时器至少执行一次,那么您可以拥有一个初始状态设置为无信号的System.Threading.ManualResetEvent[]数组
因此,在你的代码中的某个地方,你可以设置你的计时器,并且初始化相关的waithandle。
// in main setup method..
int frequencyInMs = 600000; //10 mins
Timer timer = new Timer();
timer.Elapsed += (s, e) => MyExecute();
myTimers.Add(timer)
ManualResetEvent[] _waithandles = new ManualResetEvent[10];
_waithandles[0] = new ManualResetEvent(false);
// Other timers ...
timer = new Timer();
timer.Elapsed += (s, e) => MyOtherExecute();
myTimers.Add(timer)
_waithandles[1] = new ManualResetEvent(false);
// etc, and so on for all timers
// then in each method that gets executed by the timer
// simply set ManualReset event to signalled that will unblock it.
private void MyExecute()
{
// do all my logic then when done signal the manual reset event
_waithandles[0].Set();
}
// In your main before exiting, this will cause the main thread to wait
// until all ManualResetEvents are set to signalled
WaitHandle.WaitAll(_waithandles); 如果您只想等待挂起的操作完成,那么只需将其修改为如下所示:
_waithandles[0] = new ManualResetEvent(true); // initial state set to non blocking.
private void MyExecute()
{
_waithandles[0].Reset(); // set this waithandle to block..
// do all my logic then when done signal the manual reset event
_waithandles[0].Set();
}https://stackoverflow.com/questions/9061484
复制相似问题