如何在其回拨方法中停止System.Threading.Timer
。我引用了 MSDN
,但找不到任何有用的内容。请帮忙。
答案 0 :(得分:14)
首先,回调方法必须具有范围内的计时器实例。
然后是简单的咒语
timerInstance.Change( Timeout.Infinite , Timeout.Infinite ) ;
将关闭计时器。我相信,定时器可能会在更改后再次调用回调方法,具体取决于它所处的状态。
答案 1 :(得分:4)
timer.Change(Timeout.Infinite, Timeout.Infinite);
答案 2 :(得分:2)
试试这个:
如果您愿意,可以让计时器继续触发回调方法并包含以下代码
private void CreatorLoop(object state)
{
if (Monitor.TryEnter(lockObject)
{
try
{
// Work here
}
finally
{
Monitor.Exit(lockObject);
}
}
}
也可以查看此链接:
答案 3 :(得分:1)
您只需致电myTimer.Change(Timeout.Infinite, Timeout.Infinite)
。
从技术上讲,只有第一个参数(dueTime
)需要指定为Timeout.Infinite
才能停止计时器。
有关详细信息,请参阅Timer.Change Method。
答案 4 :(得分:1)
我发现Change(Timeout.Infinite,Timeout.Infinite)不太可靠,并且使用AutoReset = false切换到System.Timers.Timer。
答案 5 :(得分:1)
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();
}
}
}