Kor*_*tak 16 c# timer callback reentrancy
我有一个System.Threading.Timer,每10毫秒调用一次适当的事件处理程序(回调).该方法本身不是可重入的,有时可能会超过10毫秒.因此,我想在方法执行期间停止计时器.
码:
private Timer _creatorTimer;
// BackgroundWorker's work
private void CreatorWork(object sender, DoWorkEventArgs e) {
_creatorTimer = new Timer(CreatorLoop, null, 0, 10);
// some other code that worker is doing while the timer is active
// ...
// ...
}
private void CreatorLoop(object state) {
// Stop timer (prevent reentering)
_creatorTimer.Change(Timeout.Infinite, 0);
/*
... Work here
*/
// Reenable timer
_creatorTimer.Change(10, 0);
}
Run Code Online (Sandbox Code Playgroud)
MSDN声明在线程池的单独线程中调用回调方法(每次定时器触发).这意味着如果我停止计时器方法中的第一件事它仍然不会阻止计时器触发并在第一个有机会停止计时器之前运行该方法的另一个实例.
也许应该锁定计时器(甚至是非重入方法本身)?在执行其回调(和非重入)方法期间阻止计时器触发的正确方法是什么?
jsw*_*jsw 46
您可以让计时器继续触发回调方法,但将不可重入的代码包装在Monitor.TryEnter/Exit中.在这种情况下无需停止/重启计时器; 重叠调用不会获得锁定并立即返回.
private void CreatorLoop(object state)
{
if (Monitor.TryEnter(lockObject))
{
try
{
// Work here
}
finally
{
Monitor.Exit(lockObject);
}
}
}
Run Code Online (Sandbox Code Playgroud)
几种可能的解决方案:
您可以通过使用Change()
原始计时器对象的方法来管理选项#2而不处理/创建新对象,但是我不确定Change()
在第一个超时到期后使用新的启动超时调用的行为是什么.那值得一两次测试.
编辑:
我做了测试 - 操作计时器作为一个可重启的单击似乎完美的工作,它比其他方法简单得多.这里有一些基于你的示例代码作为起点(一些细节可能已经改变,以便在我的机器上编译):
private Timer _creatorTimer;
// BackgroundWorker's work
private void CreatorWork(object sender, EventArgs e) {
// note: there's only a start timeout, and no repeat timeout
// so this will fire only once
_creatorTimer = new Timer(CreatorLoop, null, 1000, Timeout.Infinite);
// some other code that worker is doing while the timer is active
// ...
// ...
}
private void CreatorLoop(object state) {
Console.WriteLine( "In CreatorLoop...");
/*
... Work here
*/
Thread.Sleep( 3000);
// Reenable timer
Console.WriteLine( "Exiting...");
// now we reset the timer's start time, so it'll fire again
// there's no chance of reentrancy, except for actually
// exiting the method (and there's no danger even if that
// happens because it's safe at this point).
_creatorTimer.Change(1000, Timeout.Infinite);
}
Run Code Online (Sandbox Code Playgroud)