Ich habe ein Timer-Objekt. Ich möchte, dass es jede Minute ausgeführt wird. Insbesondere sollte es eine OnCallBack
Methode ausführen und wird inaktiv, während eine OnCallBack
Methode ausgeführt wird. Sobald eine OnCallBack
Methode beendet ist, OnCallBack
startet sie (a ) einen Timer neu.
Folgendes habe ich gerade:
private static Timer timer;
private static void Main()
{
timer = new Timer(_ => OnCallBack(), null, 0, 1000 * 10); //every 10 seconds
Console.ReadLine();
}
private static void OnCallBack()
{
timer.Change(Timeout.Infinite, Timeout.Infinite); //stops the timer
Thread.Sleep(3000); //doing some long operation
timer.Change(0, 1000 * 10); //restarts the timer
}
Es scheint jedoch nicht zu funktionieren. Es läuft alle 3 Sekunden sehr schnell. Auch wenn Sie einen Zeitraum erhöhen (1000 * 10). Es scheint, als würde es ein Auge zudrücken1000 * 10
Was habe ich falsch gemacht?
Timer.Change
: "Wenn dueTime Null (0) ist, wird die Rückrufmethode sofort aufgerufen." Sieht so aus, als wäre es Null für mich.Antworten:
Dies ist nicht die korrekte Verwendung des System.Threading.Timer. Wenn Sie den Timer instanziieren, sollten Sie fast immer Folgendes tun:
Dadurch wird der Timer angewiesen, nach Ablauf des Intervalls nur einmal zu ticken. Dann ändern Sie in Ihrer Rückruffunktion den Timer, sobald die Arbeit abgeschlossen ist, nicht vorher. Beispiel:
Daher sind keine Sperrmechanismen erforderlich, da keine Parallelität besteht. Der Timer löst den nächsten Rückruf nach Ablauf des nächsten Intervalls + der Zeit des lang laufenden Vorgangs aus.
Wenn Sie Ihren Timer mit genau N Millisekunden ausführen müssen, empfehlen wir Ihnen, die Zeit des Langzeitbetriebs mit der Stoppuhr zu messen und dann die Änderungsmethode entsprechend aufzurufen:
Ich stark fördern .NET jemand tun , und wird unter Verwendung der CLR , die nicht Jeffrey Richters Buch gelesen hat - CLR via C # , zu lesen ist , so bald wie möglich. Timer und Thread-Pools werden dort ausführlich erklärt.
quelle
private void Callback( Object state ) { // Long running operation _timer.Change( TIME_INTERVAL_IN_MILLISECONDS, Timeout.Infinite ); }
.Callback
wird möglicherweise erneut aufgerufen, bevor eine Operation abgeschlossen ist.Long running operation
das dann viel länger dauern könnteTIME_INTERVAL_IN_MILLISECONDS
. Was würde dann passieren?ThreadPool
, wenn du den Timer übergibst? Ich denke an ein Szenario, in dem ein neuer Thread erzeugt wird, um in einem bestimmten Intervall einen Job auszuführen - und dann nach Abschluss in den Thread-Pool verbannt wird.Es ist nicht notwendig, den Timer anzuhalten, siehe nette Lösung aus diesem Beitrag :
"Sie können den Timer weiterhin die Rückrufmethode auslösen lassen, aber Ihren nicht wiedereintretenden Code in einen Monitor einbinden. TryEnter / Exit. In diesem Fall muss der Timer nicht gestoppt / neu gestartet werden. Überlappende Anrufe erhalten die Sperre nicht und kehren nicht sofort zurück."
quelle
Ist die Verwendung
System.Threading.Timer
obligatorisch?Wenn nicht,
System.Timers.Timer
hat handlicheStart()
undStop()
Methoden (und eineAutoReset
Eigenschaft, die Sie auf false setzen können, so dass dieStop()
nicht benötigt wird und Sie einfachStart()
nach der Ausführung aufrufen ).quelle
Ich würde einfach tun:
Ignorieren Sie den Parameter period, da Sie versuchen, die Periodizität selbst zu steuern.
Ihr ursprünglicher Code wird so schnell wie möglich ausgeführt, da Sie immer wieder
0
dendueTime
Parameter angeben. VonTimer.Change
:quelle
Change()
Methode?Wenn du magst, benutze einen Schleifenfaden im Inneren ...
quelle