Du kannst prüfen ob ein Thread noch läuft.
Dann musst Du dich auch nicht darum kümmern, dass nur ein Thread existiert.
Einfach alle 10 Sekunden schauen, ob das Ding noch läuft.
Läuft er nicht, starte neu, ohne den Thread neu zu erstellen, sondern einfach neu starten.
Läuft er noch, warte auf die Beendigung und starte dann neu, sobald er beendet ist.
Da es kein StateChanged-Event gibt (zumindest habe ich keines gefunden), müsstest Du selber warten. Entweder die Methode blockiert (
while-Chleife, mit
Thread.Sleep(10))
Oder Du machst die Methode asynchron und startest dann einen neuen Task, der dann Wartet. Dann aber nicht mehr mit Thread.Sleep, sondern
Task.Delay(10).
So erzeugst Du nicht ständig neue Threads, was sehr teuer ist und Du sparst dir die Kontrolle, dass immer nur ein Thread läuft.
Das müsste auch mit Tasks funktionieren und ist auch besser und einfacher.
Bei Tasks hast Du auch den Vorteil, dass es die
ContinueWith-Methode gibt.
Eine spontane Idee: Währe nicht möglich, mit ContinueWith auf die Beendigung zu warten, dann warten, bis die 10 Sekunden abgelaufen sind und dann sich selber neu starten?
Nur eine Idee, getestet habe ich nichts
PS:
Ich hab mal ein Beispiel gebastelt. Hat sicherlich Verbesserungsbedarf von Jemandem, der mehr Erfahrung damit hat.
Es ist außerdem nur ein Beispiel, in einem Produktiv-System würde ich das nicht einbauen - schon allein wegen den Konsolenausgaben.
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56:
| public class LoopTaskRunner { private readonly Func<CancellationToken, Task> _asyncAction; private readonly object _lock = new object(); private DateTime _lastStart;
public DateTime LastStart { get { lock (_lock) return _lastStart; } private set { lock (_lock) _lastStart = value; } }
public TimeSpan DelayForNextStart { get; }
public LoopTaskRunner(Func<CancellationToken, Task> asyncAction, TimeSpan delayForNextStart) { _asyncAction = asyncAction; DelayForNextStart = delayForNextStart; } public async Task RunAsync(CancellationToken cancellationToken) { var counter = 0;
while (!cancellationToken.IsCancellationRequested) { counter++;
await Task.Factory.StartNew(async () => { LastStart = DateTime.Now; Console.WriteLine($"{counter}: {DateTime.Now} | Starting");
await _asyncAction(cancellationToken);
Console.WriteLine(); Console.WriteLine($"{counter}: {DateTime.Now} | {(cancellationToken.IsCancellationRequested ? "Cancled" : "Finished")}"); Console.WriteLine(new string('=', 20));
if (!cancellationToken.IsCancellationRequested) { while (DateTime.Now - LastStart < DelayForNextStart) await Task.Delay(50); } }).Unwrap(); } } } |
Die Nutzung:
C#-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28:
| static void Main(string[] args) { DoSomethingAsync();
Console.ReadKey(); }
static async Task DoSomethingAsync() { var runner = new LoopTaskRunner(async token => { for (int i = 0; i < 10; i++) { if (token.IsCancellationRequested) break;
Console.Write(i); await Task.Delay(200); } }, TimeSpan.FromSeconds(5));
var cancellationTokenSource = new CancellationTokenSource();
var _ = runner.RunAsync(cancellationTokenSource.Token);
await Task.Delay(TimeSpan.FromSeconds(11)); cancellationTokenSource.Cancel(); } |
Die Ausgabe sieht bei mir so aus:
Zitat: |
1: 08.02.2016 13:10:02 | Starting
0123456789
1: 08.02.2016 13:10:04 | Finished
====================
2: 08.02.2016 13:10:07 | Starting
0123456789
2: 08.02.2016 13:10:09 | Finished
====================
3: 08.02.2016 13:10:12 | Starting
01234
3: 08.02.2016 13:10:13 | Cancled
==================== |