如何在回调方法中停止System.Threading.Timer

时间:2012-08-13 16:33:24

标签: c# multithreading timer

如何在其回拨方法中停止System.Threading.Timer。我引用了 MSDN ,但找不到任何有用的内容。请帮忙。

6 个答案:

答案 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); 
     } 
   } 
 } 

也可以查看此链接:

Stopping timer in its callback method

答案 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();
        }
    }
}