10
votes

Comment arrêter System.threading.Timer dans la méthode de rappel

Comment puis-je arrêter system.threading.timer dans sa méthode de rappelle. J'ai référencé msdn , mais je n'ai rien trouvé utile. S'il vous plaît aider.


6 Réponses :


4
votes
timer.Change(Timeout.Infinite, Timeout.Infinite);

1 commentaires

Et si je veux le redémarrer plus tard?



1
votes

Vous pouvez simplement appeler mytimer.change (timeout.infinite, timeout.infinite) .

Techniquement, seul le premier paramètre ( duetime ) doit être spécifié comme timeout.infinite pour la minuterie à arrêter.

Pour plus d'informations, voir méthode Timer.change .


2 commentaires

Il vaut mieux le disposer parce que cela capture le sens sémantique mieux. Cela pourrait aussi être plus rapide.


Cela dépend de si l'utilisateur arrête de manière permanente la minuterie, ou si elle le fait la pause pendant un temps et éventuellement le redémarrer ultérieurement. Si vous utilisez .Dispose () Pour simplement mettre en pause la minuterie, vous rencontrerez des problèmes si vous souhaitez le redémarrer ou simplement changer le duetime ou la période. Dans ces cas, il est plus sûr (et plus facile) d'utiliser Timer.changer () .



2
votes

Essayez ceci:

Si vous voulez que vous puissiez laisser la minuterie continuer à tirer la méthode de rappel et inclure le code ci-dessous xxx

Consultez ce lien aussi:

arrêt de la minuterie dans sa méthode de rappel


0 commentaires

15
votes

Premièrement, la méthode de rappel doit avoir l'instance de minuterie.

L'incantation simple xxx

fera fermer la minuterie. Il est possible que la minuterie puisse invoquer une méthode de rappel une fois de plus après le changement, je crois, en fonction de l'état.


3 commentaires

Il vaut mieux le disposer parce que cela capture le sens sémantique mieux. Cela pourrait aussi être plus rapide.


Dépend de la question de savoir si la minuterie doit être redémarrée plus tard ou que vous en avez terminé. L'OP a précisé qu'elle voulait "arrêter la minuterie", pas "Détruire la minuterie". L'instance de minuterie et sa vie sont la responsabilité de son créateur.


Yap avec cette solution qui est le problème, le fil ne s'arrête pas immédiatement.



1
votes

J'ai découvert la solution difficile qui change (timeout.infinite, timeout.infinite) n'est pas assez fiable et passée à System.Timers.Timer avec Auteset = Faux.


0 commentaires

1
votes

Le problème avec la minuterie est qu'il pourrait être appelé après disposition de sa classe propriétaire. La mise en œuvre suivante a fonctionné pour moi en utilisant l'objet État de l'initialisateur de la minuterie. Le tas ne supprimera pas cet objet jusqu'à ce qu'il soit consommé. C'était mon seul moyen de nettoyer gracieusement le rappel de la minuterie.

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


0 commentaires