C# 如何在回调方法中停止 System.Threading.Timer
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11938471/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to stop System.Threading.Timer in callback method
提问by Proceso
How can I stop System.Threading.Timerin it's call back method. I referenced MSDN, but couldn't find anything useful. Please help.
我怎样才能停止System.Threading.Timer它的回调方法。我参考了MSDN,但找不到任何有用的东西。请帮忙。
回答by Volma
timer.Change(Timeout.Infinite, Timeout.Infinite);
回答by Jon Senchyna
You can simply call myTimer.Change(Timeout.Infinite, Timeout.Infinite).
您可以简单地调用myTimer.Change(Timeout.Infinite, Timeout.Infinite).
Technically, only the first parameter (dueTime) needs to be specified as Timeout.Infinitefor the timer to stop.
从技术上讲,只需指定第一个参数 ( dueTime)Timeout.Infinite即可停止计时器。
For more information, see Timer.Change Method.
有关更多信息,请参阅Timer.Change 方法。
回答by LOZ
Try this:
尝试这个:
If you want you could let timer continue firing the callback method and include the code below
如果您愿意,您可以让计时器继续触发回调方法并包含以下代码
private void CreatorLoop(object state)
{
if (Monitor.TryEnter(lockObject)
{
try
{
// Work here
}
finally
{
Monitor.Exit(lockObject);
}
}
}
check out this link too:
也看看这个链接:
回答by Nicholas Carey
First, the callback method must have the timer instance in-scope.
首先,回调方法必须在范围内具有计时器实例。
Then the simple incantation
然后是简单的咒语
timerInstance.Change( Timeout.Infinite , Timeout.Infinite ) ;
will shut down the timer. It is possible that the timer might invoke the callback method once more after the change, I believe, depending on the state it's in.
将关闭计时器。我相信,计时器可能会在更改后再次调用回调方法,这取决于它所处的状态。
回答by Mark Sowul
I found out the hard way that Change(Timeout.Infinite, Timeout.Infinite) isn't quite reliable, and switched over to System.Timers.Timer with AutoReset = false.
我发现 Change(Timeout.Infinite, Timeout.Infinite) 不是很可靠,并切换到 System.Timers.Timer 并使用 AutoReset = false。
回答by Ibrahim
The problem with Timer is that it might be called after disposing its owner class. The following implementation worked for me by using the state object of the Timer initializer. Heap will not remove that object until it is consumed. This was my only way to gracefully cleanup timer callback.
Timer 的问题在于它可能在处理其所有者类后被调用。以下实现通过使用 Timer 初始值设定项的状态对象对我有用。堆不会删除该对象,直到它被消耗。这是我优雅地清理计时器回调的唯一方法。
using System;
using System.Threading;
namespace TimerDispose
{
/// <summary>
/// A timer-containing class that can be disposed safely by allowing the timer
/// callback that it must exit/cancel its processes
/// </summary>
class TimerOwner : IDisposable
{
const int dueTime = 5 * 100; //halve a second
const int timerPeriod = 1 * 1000; //Repeat timer every one second (make it Timeout.Inifinite if no repeating required)
private TimerCanceller timerCanceller = new TimerCanceller();
private Timer timer;
public TimerOwner()
{
timerInit(dueTime);
}
byte[] dummy = new byte[100000];
/// <summary>
///
/// </summary>
/// <param name="dueTime">Pass dueTime for the first time, then TimerPeriod will be passed automatically</param>
private void timerInit(int dueTime)
{
timer = new Timer(timerCallback,
timerCanceller, //this is the trick, it will be kept in the heap until it is consumed by the callback
dueTime,
Timeout.Infinite
);
}
private void timerCallback(object state)
{
try
{
//First exit if the timer was stoped before calling callback. This info is saved in state
var canceller = (TimerCanceller)state;
if (canceller.Cancelled)
{
return; //
}
//Your logic goes here. Please take care ! the callback might have already been called before stoping the timer
//and we might be already here after intending of stoping the timer. In most cases it is fine but try not to consume
//an object of this class because it might be already disposed. If you have to do that, hopefully it will be catched by
//the ObjectDisposedException below
dummy[1] = 50; //just messing up with the object after it might be disposed/nulled
//Yes, we need to check again. Read above note
if (canceller.Cancelled)
{
//Dispose any resource that might have been initialized above
return; //
}
if (timerPeriod != Timeout.Infinite)
{
timerInit(timerPeriod);
}
}
catch (ObjectDisposedException ex)
{
Console.WriteLine("A disposed object accessed");
}
catch (NullReferenceException ex)
{
Console.WriteLine("A nulled object accessed");
}
catch (Exception ex)
{
}
}
public void releaseTimer()
{
timerCanceller.Cancelled = true;
timer.Change(Timeout.Infinite, Timeout.Infinite);
timer.Dispose();
}
public void Dispose()
{
releaseTimer();
dummy = null; //for testing
GC.SuppressFinalize(this);
}
}
class TimerCanceller
{
public bool Cancelled = false;
}
/// <summary>
/// Testing the implementation
/// </summary>
class Program
{
static void Main(string[] args)
{
var list = new System.Collections.Generic.List<TimerOwner>();
Console.WriteLine("Started initializing");
for (int i = 0; i < 500000; i++)
{
list.Add(new TimerOwner());
}
Console.WriteLine("Started releasing");
foreach (var item in list)
{
item.Dispose();
}
Console.WriteLine("Press any key to exit");
Console.ReadKey();
}
}
}

