Reputation: 77
I set a timer logic in Main program to AutorReset every 30 seconds, so my LogCollection method (which extract data) will loop every 30 seconds and my code can keep going on.
The problem is that I realized that sometimes the time given is shorter than the method execution time which cause multiple method calls at the same time which results multiple data flood.
Q: How can I make the timer wait and no to do another cycle before the method finished?
Timer code looks like:
Timer thetimer = new Timer(TimeSpan.FromSeconds(30).TotalMilliseconds);
thetimer.Elapsed += new System.Timers.ElapsedEventHandler(LogCollector.LogCollection);
thetimer.AutoReset = true;
thetimer.Start();
I was thinking to add some While loop but than my code would loop on that forever and the rest of the code would not complete. Please advise
Upvotes: 0
Views: 160
Reputation: 20373
I would abandon Timer
and use async
instead:
while (true)
{
var start = DateTime.Now;
LogCollector.LogCollection();
var timeRemaining = TimeSpan.FromSeconds(30) - (DateTime.Now - start);
await Task.Delay(Math.Max(timeRemaining.TotalMilliseconds, 0));
}
Math.Max
is used in case the execution of LogCollection()
exceeds 30 seconds, in which case timeRemaining
would be negative.
If you have code to run after the loop, move it into a cancellable method:
async Task LogCollectionLoopAsync(TimeSpan minLoopTime, CancellationToken ct)
{
while (!ct.IsCancellationRequested)
{
var start = DateTime.Now;
LogCollector.LogCollection();
var timeRemaining = minLoopTime - (DateTime.Now - start);
await Task.Delay(Math.Max(timeRemaining.TotalMilliseconds, 0), ct);
}
}
Then your Main
method could be written like this:
async Task Main()
{
var cts = new CancellationTokenSource();
var logCollectionTask = LogCollectionLoopAsync(TimeSpan.FromSeconds(30), cts.Token);
// Do your other stuff
cts.Cancel();
try { await logCollectionTask; } catch { } // Cancellation causes an exception
}
Upvotes: 1