11
votes

Application de réveil dans .NET

Je n'écris pas vraiment une application de réveil, mais cela aidera à illustrer ma question.

Disons que j'ai une méthode dans ma candidature et que je souhaite que cette méthode soit appelée toutes les heures sur l'heure (par exemple à 19h00, 20h00, 21h00, etc.). Je pourrait créer une minuterie et définir son intervalle sur 3600000, mais éventuellement, cela déroulerait de la synchronisation avec l'horloge système. Ou i pourrait utiliser utiliser un tandis que () boucle avec thread.sleep (n) Pour vérifier périodiquement l'heure du système et appeler la méthode lorsque la méthode souhaitée Le temps est atteint, mais je n'aime pas cela non plus ( thread.sleep (n) est une grosse odeur de code pour moi).

Ce que je recherche, c'est une méthode de .net qui me permet de passer à un futur objet DateTime et d'une méthode déléguée ou gestionnaire d'événements, mais je n'ai pas pu trouver de telles choses. Je soupçonne qu'il y a une méthode dans l'API Win32 qui le fait, mais je n'ai pas été en mesure de le trouver non plus.


4 commentaires

Cherches-tu à rouler votre propre quartz.net? Quartznet.sourceforge.net


@Austin: Non, je suis juste à la recherche d'une méthode simple comme ce que je décris dans le dernier paragraphe, sans avoir à rouler la mienne ou à utiliser une composante tierce partie.


Le planificateur intégré Windows a une API accessible via Pinvoke Pinvoke.net/Default.aspx /NETAPI32/NETSCHEDULEJOBADD.HTML


@XCUD: Netschedulejobadd est proche de ce que je cherche, mais il exécute une chaîne de commande plutôt que d'appeler une méthode.


7 Réponses :


12
votes

ou, vous pouvez créer une minuterie avec un intervalle de 1 seconde et vérifier l'heure actuelle chaque seconde jusqu'à ce que l'heure de l'événement soit atteinte, si oui, vous soulevez votre événement.

Vous pouvez faire une simple emballage pour cela: P>

AlarmClock clock = new AlarmClock(someFutureTime);
clock.Alarm += (sender, e) => MessageBox.Show("Wake up!");


7 commentaires

Ouais, mais ce n'est pas non plus ce que je cherche, désolé.


Ce que vous cherchez n'existe pas.


Désolé mais, que cherchez-vous alors?


Je pense que la musigganèse veut vraiment un planificateur de travail.


Vous pouvez calculer l'intervalle plutôt que de vérifier chaque seconde.


@JONB: Comme expliqué dans la question, il veut quelque chose qui ne dérive pas.


@COINCOIN: Cette approche peut être la seule façon d'y parvenir à Windows, mais j'espérais au moins un appel d'API Win32 qui le fait (comme Netschedulejobadd mentionné par XCUD , bien que cette fonction exécute une commande à l'heure prévue au lieu d'appeler une méthode particulière dans un processus de fonctionnement particulier).



1
votes

Vous pouvez créer une classe d'alarme qui a un fil dédié qui va dormir jusqu'à l'heure spécifiée, mais cela utilisera la méthode thread.sleep. Quelque chose comme: xxx


1 commentaires

En effet. Plus d'un prototype de ce que vous pourriez faire. Mieux vaut utiliser une minuterie comme Jacob décrit.



2
votes

Vous pouvez simplement réinitialiser la durée de la minuterie chaque fois qu'il tire, comme ceci:

// using System.Timers;

private void myMethod()
{
    var timer = new Timer { 
        AutoReset = false, Interval = getMillisecondsToNextAlarm() };
    timer.Elapsed += (src, args) =>
    {
        // Do timer handling here.

        timer.Interval = getMillisecondsToNextAlarm();
        timer.Start();
    };
    timer.Start();
}

private double getMillisecondsToNextAlarm()
{
    // This is an example of making the alarm go off at every "o'clock"
    var now = DateTime.Now;
    var inOneHour = now.AddHours(1.0);
    var roundedNextHour = new DateTime(
        inOneHour.Year, inOneHour.Month, inOneHour.Day, inOneHour.Hour, 0, 0);
    return (roundedNextHour - now).TotalMilliseconds;
}


5 commentaires

Cela ne résoudrait pas malheureusement le problème. Le problème de la dérive est que la minuterie est inexacte sur de longues durées (chronomètre a le même problème).


Je n'avais jamais entendu ça avant. Qu'est-ce que vous basez que l'inexactitude prétendez-vous?


@Jacob: Ne prenez pas mon mot pour cela - essayez-le vous-même. Commencez une minuterie (n'importe quelle variété) et laissez-la courir pendant une journée ou deux, et voyez à quel point il obtient.


Je ne reçois pas ce problème "dérive". J'ai utilisé un système.Timers.Timer avec une heure écoulée de cinq secondes au cours d'un service et n'avait aucune dérive au cours des quatre mois que je l'ai utilisée. Je sais que ceci pour un fait que le service a écrit au journal des événements sur chaque intervalle, et j'ai des événements toutes les cinq secondes telles que les horlogères, qui étaient attendues.


@Amissico: Votre service n'a-t-il que votre service que la minuterie une fois, écrit ensuite sur le journal des événements sur chaque appel écoulé ou votre service a-t-il été rétabli périodiquement par Windows? Je viens de tester cela à nouveau, et ma minuterie (avec un intervalle de 5000) dérivait de la durée du système à une seconde complète après seulement 12 minutes.



-1
votes

Qu'en est-il de la classe System.Timers.Timer? Voir http://msdn.microsoft.com/en-us /Library/system.timers.timer.aspx


1 commentaires

Non, ça ne fait rien comme ce que je cherche.



8
votes

intéressant, j'ai rencontré un problème très similaire et je suis allé chercher une méthode dans le cadre .NET qui gérerait ce scénario. En fin de compte, nous avons fini par mettre en œuvre notre propre solution qui a été une variante sur une boucle tandis que whong.sleep (n) où n devient plus petit, plus vous rapprochez le temps de cible souhaité (logarithmiquement réellement, mais avec des seuils raisonnables, mais Vous ne maxez pas la CPU lorsque vous vous approchez de l'heure cible.) Voici une implémentation très simple qui ne peut que dormir la moitié du temps entre maintenant et le temps cible.

class Program
{
    static void Main(string[] args)
    {
        SleepToTarget Temp = new SleepToTarget(DateTime.Now.AddSeconds(30),Done);
        Temp.Start();
        Console.ReadLine();
    }

    static void Done()
    {
        Console.WriteLine("Done");
    }
}

class SleepToTarget
{
    private DateTime TargetTime;
    private Action MyAction;
    private const int MinSleepMilliseconds = 250;

    public SleepToTarget(DateTime TargetTime,Action MyAction)
    {
        this.TargetTime = TargetTime;
        this.MyAction = MyAction;
    }

    public void Start()
    {
        new Thread(new ThreadStart(ProcessTimer)).Start();
    }

    private void ProcessTimer()
    {
        DateTime Now = DateTime.Now;

        while (Now < TargetTime)
        {
            int SleepMilliseconds = (int) Math.Round((TargetTime - Now).TotalMilliseconds / 2);
            Console.WriteLine(SleepMilliseconds);
            Thread.Sleep(SleepMilliseconds > MinSleepMilliseconds ? SleepMilliseconds : MinSleepMilliseconds);
            Now = DateTime.Now;
        }

        MyAction();
    }
}


0 commentaires

-2
votes

J'ai utilisé cela avant avec beaucoup de succès:

vb.net: p> xxx pré>

c #: p> xxx pré>

Je ne sais pas si le C # fonctionne, mais le VB fonctionne juste bien. P>

Utilisation dans VB: P>

Dim clock As New AlarmClock
clock.interval = 1 'Interval is in hours, could easily convert to anything else
clock.StartClock()


3 commentaires

TimeOnday est une chose VB.NET uniquement et le pendant avec un DoEvents () Appelez votre processeur tandis que cette chose est en cours d'exécution.


Je ne savais pas ça, mais maintenant je fais. Le code d'origine avait la boucle de sommeil pendant 15 secondes, mais puisque vous ne vouliez pas que je l'ai laissée.


POURQUOI VOUS VOULEZ DE L'APPLICATION. Doevents dans une méthode exécutée dans un fil (ou même du tout) est au-delà de moi



1
votes

Je sais que c'est un peu une vieille question, mais je suis tombé sur cela quand je cherchais une réponse à autre chose. Je pensais que je jetais mes deux cents ici, depuis que j'ai récemment eu ce problème particulier.

Une autre chose que vous pouvez faire est de planifier la méthode, comme: xxx

Gardant à l'esprit, il ne peut attendre que la valeur maximale de INT 32 (quelque part environ un mois), cela devrait fonctionner à vos besoins. Utilisation: xxx

et vous devez avoir un message de console dans une heure.


0 commentaires