Just this - How do you add a timer to a C# console application? It would be great if you could supply some example coding.
That's very nice, however in order to simulate some time passing we need to run a command that takes some time and that's very clear in second example.
However, the style of using a for loop to do some functionality forever takes a lot of device resources and instead we can use the Garbage Collector to do some thing like that.
We can see this modification in the code from the same book CLR Via C# Third Ed.
using System;
using System.Threading;
public static class Program
{
private Timer _timer = null;
public static void Main()
{
// Create a Timer object that knows to call our TimerCallback
// method once every 2000 milliseconds.
_timer = new Timer(TimerCallback, null, 0, 2000);
// Wait for the user to hit <Enter>
Console.ReadLine();
}
private static void TimerCallback(Object o)
{
// Display the date/time when this method got called.
Console.WriteLine("In TimerCallback: " + DateTime.Now);
}
}
Use the System.Threading.Timer class.
System.Windows.Forms.Timer is designed primarily for use in a single thread usually the Windows Forms UI thread.
There is also a System.Timers class added early on in the development of the .NET framework. However it is generally recommended to use the System.Threading.Timer class instead as this is just a wrapper around System.Threading.Timer anyway.
It is also recommended to always use a static (shared in VB.NET) System.Threading.Timer if you are developing a Windows Service and require a timer to run periodically. This will avoid possibly premature garbage collection of your timer object.
Here's an example of a timer in a console application:
using System;
using System.Threading;
public static class Program
{
public static void Main()
{
Console.WriteLine("Main thread: starting a timer");
Timer t = new Timer(ComputeBoundOp, 5, 0, 2000);
Console.WriteLine("Main thread: Doing other work here...");
Thread.Sleep(10000); // Simulating other work (10 seconds)
t.Dispose(); // Cancel the timer now
}
// This method's signature must match the TimerCallback delegate
private static void ComputeBoundOp(Object state)
{
// This method is executed by a thread pool thread
Console.WriteLine("In ComputeBoundOp: state={0}", state);
Thread.Sleep(1000); // Simulates other work (1 second)
// When this method returns, the thread goes back
// to the pool and waits for another task
}
}
From the book CLR Via C# by Jeff Richter. By the way this book describes the rationale behind the 3 types of timers in Chapter 23, highly recommended.
Here is the code to create a simple one second timer tick:
using System;
using System.Threading;
class TimerExample
{
static public void Tick(Object stateInfo)
{
Console.WriteLine("Tick: {0}", DateTime.Now.ToString("h:mm:ss"));
}
static void Main()
{
TimerCallback callback = new TimerCallback(Tick);
Console.WriteLine("Creating timer: {0}\n",
DateTime.Now.ToString("h:mm:ss"));
// create a one second timer tick
Timer stateTimer = new Timer(callback, null, 0, 1000);
// loop here forever
for (; ; )
{
// add a sleep for 100 mSec to reduce CPU usage
Thread.Sleep(100);
}
}
}
And here is the resulting output:
c:\temp>timer.exe
Creating timer: 5:22:40
Tick: 5:22:40
Tick: 5:22:41
Tick: 5:22:42
Tick: 5:22:43
Tick: 5:22:44
Tick: 5:22:45
Tick: 5:22:46
Tick: 5:22:47
EDIT: It is never a good idea to add hard spin loops into code as they consume CPU cycles for no gain. In this case that loop was added just to stop the application from closing, allowing the actions of the thread to be observed. But for the sake of correctness and to reduce the CPU usage a simple Sleep call was added to that loop.
Lets Have A little Fun
using System;
using System.Timers;
namespace TimerExample
{
class Program
{
static Timer timer = new Timer(1000);
static int i = 10;
static void Main(string[] args)
{
timer.Elapsed+=timer_Elapsed;
timer.Start(); Console.Read();
}
private static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
i--;
Console.Clear();
Console.WriteLine("=================================================");
Console.WriteLine(" DEFUSE THE BOMB");
Console.WriteLine("");
Console.WriteLine(" Time Remaining: " + i.ToString());
Console.WriteLine("");
Console.WriteLine("=================================================");
if (i == 0)
{
Console.Clear();
Console.WriteLine("");
Console.WriteLine("==============================================");
Console.WriteLine(" B O O O O O M M M M M ! ! ! !");
Console.WriteLine("");
Console.WriteLine(" G A M E O V E R");
Console.WriteLine("==============================================");
timer.Close();
timer.Dispose();
}
GC.Collect();
}
}
}
Or using Rx, short and sweet:
static void Main()
{
Observable.Interval(TimeSpan.FromSeconds(10)).Subscribe(t => Console.WriteLine("I am called... {0}", t));
for (; ; ) { }
}
You can also use your own timing mechanisms if you want a little more control, but possibly less accuracy and more code/complexity, but I would still recommend a timer. Use this though if you need to have control over the actual timing thread:
private void ThreadLoop(object callback)
{
while(true)
{
((Delegate) callback).DynamicInvoke(null);
Thread.Sleep(5000);
}
}
would be your timing thread(modify this to stop when reqiuired, and at whatever time interval you want).
and to use/start you can do:
Thread t = new Thread(new ParameterizedThreadStart(ThreadLoop));
t.Start((Action)CallBack);
Callback is your void parameterless method that you want called at each interval. For example:
private void CallBack()
{
//Do Something.
}
You can also create your own (if unhappy with the options available).
Creating your own Timer implementation is pretty basic stuff.
This is an example for an application that needed COM object access on the same thread as the rest of my codebase.
/// <summary>
/// Internal timer for window.setTimeout() and window.setInterval().
/// This is to ensure that async calls always run on the same thread.
/// </summary>
public class Timer : IDisposable {
public void Tick()
{
if (Enabled && Environment.TickCount >= nextTick)
{
Callback.Invoke(this, null);
nextTick = Environment.TickCount + Interval;
}
}
private int nextTick = 0;
public void Start()
{
this.Enabled = true;
Interval = interval;
}
public void Stop()
{
this.Enabled = false;
}
public event EventHandler Callback;
public bool Enabled = false;
private int interval = 1000;
public int Interval
{
get { return interval; }
set { interval = value; nextTick = Environment.TickCount + interval; }
}
public void Dispose()
{
this.Callback = null;
this.Stop();
}
}
You can add events as follows:
Timer timer = new Timer();
timer.Callback += delegate
{
if (once) { timer.Enabled = false; }
Callback.execute(callbackId, args);
};
timer.Enabled = true;
timer.Interval = ms;
timer.Start();
Window.timers.Add(Environment.TickCount, timer);
To make sure the timer works you need to create an endless loop as follows:
while (true) {
// Create a new list in case a new timer
// is added/removed during a callback.
foreach (Timer timer in new List<Timer>(timers.Values))
{
timer.Tick();
}
}
In C# 5.0+ and .NET Framework 4.5+ you can use async/await:
async void RunMethodEvery(Action method, double seconds)
{
while (true)
{
await Task.Delay(TimeSpan.FromSeconds(seconds));
method();
}
}
Use the PowerConsole project on Github at https://github.com/bigabdoul/PowerConsole or the equivalent NuGet package at https://www.nuget.org/packages/PowerConsole. It elegantly handles timers in a reusable fashion. Take a look at this sample code:
using PowerConsole;
namespace PowerConsoleTest
{
class Program
{
static readonly SmartConsole MyConsole = SmartConsole.Default;
static void Main()
{
RunTimers();
}
public static void RunTimers()
{
// CAUTION: SmartConsole is not thread safe!
// Spawn multiple timers carefully when accessing
// simultaneously members of the SmartConsole class.
MyConsole.WriteInfo("\nWelcome to the Timers demo!\n")
// SetTimeout is called only once after the provided delay and
// is automatically removed by the TimerManager class
.SetTimeout(e =>
{
// this action is called back after 5.5 seconds; the name
// of the timer is useful should we want to clear it
// before this action gets executed
e.Console.Write("\n").WriteError("Time out occured after 5.5 seconds! " +
"Timer has been automatically disposed.\n");
// the next statement will make the current instance of
// SmartConsole throw an exception on the next prompt attempt
// e.Console.CancelRequested = true;
// use 5500 or any other value not multiple of 1000 to
// reduce write collision risk with the next timer
}, millisecondsDelay: 5500, name: "SampleTimeout")
.SetInterval(e =>
{
if (e.Ticks == 1)
{
e.Console.WriteLine();
}
e.Console.Write($"\rFirst timer tick: ", System.ConsoleColor.White)
.WriteInfo(e.TicksToSecondsElapsed());
if (e.Ticks > 4)
{
// we could remove the previous timeout:
// e.Console.ClearTimeout("SampleTimeout");
}
}, millisecondsInterval: 1000, "EverySecond")
// we can add as many timers as we want (or the computer's resources permit)
.SetInterval(e =>
{
if (e.Ticks == 1 || e.Ticks == 3) // 1.5 or 4.5 seconds to avoid write collision
{
e.Console.WriteSuccess("\nSecond timer is active...\n");
}
else if (e.Ticks == 5)
{
e.Console.WriteWarning("\nSecond timer is disposing...\n");
// doesn't dispose the timer
// e.Timer.Stop();
// clean up if we no longer need it
e.DisposeTimer();
}
else
{
System.Diagnostics.Trace.WriteLine($"Second timer tick: {e.Ticks}");
}
}, 1500)
.Prompt("\nPress Enter to stop the timers: ")
// makes sure that any remaining timer is disposed off
.ClearTimers()
.WriteSuccess("Timers cleared!\n");
}
}
}
doc
There you have it :)
public static void Main()
{
SetTimer();
Console.WriteLine("\nPress the Enter key to exit the application...\n");
Console.WriteLine("The application started at {0:HH:mm:ss.fff}", DateTime.Now);
Console.ReadLine();
aTimer.Stop();
aTimer.Dispose();
Console.WriteLine("Terminating the application...");
}
private static void SetTimer()
{
// Create a timer with a two second interval.
aTimer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
e.SignalTime);
}
I suggest you following Microsoft guidelines (
https://learn.microsoft.com/en-us/dotnet/api/system.timers.timer.interval?view=netcore-3.1).
I first tried using System.Threading; with
var myTimer = new Timer((e) =>
{
// Code
}, null, TimeSpan.Zero, TimeSpan.FromSeconds(5));
but it continuously stopped after ~20 minutes.
With that, I tried the solutions setting
GC.KeepAlive(myTimer)
or
for (; ; ) { }
}
but they didn't work in my case.
Following Microsoft documentation, it worked perfectly:
using System;
using System.Timers;
public class Example
{
private static Timer aTimer;
public static void Main()
{
// Create a timer and set a two second interval.
aTimer = new System.Timers.Timer();
aTimer.Interval = 2000;
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
// Have the timer fire repeated events (true is the default)
aTimer.AutoReset = true;
// Start the timer
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program at any time... ");
Console.ReadLine();
}
private static void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}
// The example displays output like the following:
// Press the Enter key to exit the program at any time...
// The Elapsed event was raised at 5/20/2015 8:48:58 PM
// The Elapsed event was raised at 5/20/2015 8:49:00 PM
// The Elapsed event was raised at 5/20/2015 8:49:02 PM
// The Elapsed event was raised at 5/20/2015 8:49:04 PM
// The Elapsed event was raised at 5/20/2015 8:49:06 PM
you can use StopWatch class, here's an example
StopWatch stopwatch = new Stopwatch();
// creating a new stopwatch class
stopwatch.Start();
// starting the stopwatch
Thread.Sleep(10000);
// waiting for 10 seconds
TimeSpan timespan = stopwatch.Elapsed;
/* creating a new timespan class and concacting it with the elapsed of the
stopwatch class */
string time = String.Format("{0:00}:{1:00}:{2:00}",
timespan.Hours, timespan.Minutes, timespan.Seconds
);
Console.Write($"The time right now is {time}");
Console.ReadKey();
Related
I want to build a simple API which just displays some data using the controller. The controller displays some dummy data using genfu and at the moment it is all retrieved at once, what i need to do is display each record after a certain amount of time, like, the first time i run the application i want 0 results, than, after one sec for example, the next one and so on, here's what i have so far in the controller, it's really really basic
// GET: api/<controller>
[HttpGet]
public IEnumerable<Contact> Get()
{
var data = _contactsGeneratorService.Collection(100);
return data;
}
I tried to use the thread.sleep option but it doesn't work in this case. Sorry, I am really really new to this.
Look into the C# Timer Control/Class. Here is an example from Microsoft's documentation:
using System;
using System.Timers;
public class Example
{
private static System.Timers.Timer aTimer;
public static void Main()
{
SetTimer();
Console.WriteLine("\nPress the Enter key to exit the application...\n");
Console.WriteLine("The application started at {0:HH:mm:ss.fff}", DateTime.Now);
Console.ReadLine();
aTimer.Stop();
aTimer.Dispose();
Console.WriteLine("Terminating the application...");
}
private static void SetTimer()
{
// Create a timer with a two second interval.
aTimer = new System.Timers.Timer(2000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += OnTimedEvent;
aTimer.AutoReset = true;
aTimer.Enabled = true;
}
private static void OnTimedEvent(Object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0:HH:mm:ss.fff}",
e.SignalTime);
}
}
For more examples, see this article: http://csharp.net-informations.com/gui/timer-cs.htm
Usually I avoid using Thread.Sleep except for testing or debugging code.
In the following example, I'm trying to run a console app which will run different classes that will trigger timer ticks at certain times. The idea is to add many more classes that run independent services.
At the moment I'm using, Thread.Sleep(10000); just to keep the console open to allow the code to run.
Surely the Thread.Sleep is blocking some resouces of the CPU?
Is there a better way? (This would be for both Windows and Linux)
while(true)
{
Thread.Sleep(10000);
}
Program:
class Program
{
private static CultureInfo culture = new CultureInfo("en-gb");
static void Main(string[] args)
{
LongRunningClass longRunningClass = new LongRunningClass();
while(true)
{
Thread.Sleep(10000);
}
}
}
Long Running Task:
public class LongRunningClass
{
private Timer timer;
private List<TimeSpan> ScheduleTimes = new List<TimeSpan>()
{
new TimeSpan(4,0,0),
new TimeSpan(6,0,0),
new TimeSpan(21,0,0),
new TimeSpan(23,0,0),
};
public LongRunningClass()
{
this.timer = new Timer(1000);
this.timer.Elapsed += new ElapsedEventHandler(OnTick);
this.timer.Start();
}
protected virtual void OnTick(object sender, ElapsedEventArgs e)
{
this.timer.Stop();
RunLongRunningTask();
double nextTickInterval = 0;
TimeSpan timeOfDayNow = DateTime.Now.TimeOfDay;
foreach (TimeSpan scheduleTime in ScheduleTimes)
{
if (scheduleTime > timeOfDayNow)
{
nextTickInterval = (scheduleTime - timeOfDayNow).TotalMilliseconds;
break;
}
}
// If tick interval not set yet then restart for next day
if (nextTickInterval <= 0)
{
TimeSpan scheduleTime = ScheduleTimes[0].Add(new TimeSpan(1, 0, 0, 0));
nextTickInterval = (scheduleTime - timeOfDayNow).TotalMilliseconds;
}
this.timer.Interval = nextTickInterval;
this.timer.Start();
}
private void RunLongRunningTask()
{
// Long Running Task
}
}
If it's about keeping the console open.
Did you try?
while(true)
{
Console.Read();
}
or just:
Console.Read();
so, it wouldn't close unless you press a key.
You can keep the console open indefinitely until the user cancels by using an AutoResetEvent:
class Program
{
private static AutoResetEvent autoResetEvent;
private static CultureInfo culture = new CultureInfo("en-gb");
static void Main(string[] args)
{
LongRunningClass longRunningClass = new LongRunningClass();
WaitForCancel();
}
/// <summary>
/// When cancel keys Ctrl+C or Ctrl+Break are used, set the event.
/// </summary>
private static void WaitForCancel()
{
autoResetEvent = new AutoResetEvent(false);
Console.WriteLine("Press CTRL + C or CTRL + Break to exit...");
Console.CancelKeyPress += (sender, e) =>
{
e.Cancel = true;
autoResetEvent.Set();
};
autoResetEvent.WaitOne();
}
}
Obviously, this method relies on you knowing when your threads have finished processing.
Surely the Thread.Sleep is blocking some resouces of the CPU?
Its not the CPU you have to worry about, its the memory. You can read the complicated version here, but the simple version is that each thread uses 1MB of memory for the stack. If you are writing an application which needs a lot of threads then you should consider writing async Methods and using Task.Delay. This allows the thread to do something else while the method is waiting, which can reduce the total number of threads needed to process the same workload.
In this case however there isn't much point - while C# 7.1 does support async Main, its just syntactic sugar and doesn't free the thread up to perform other work. In any case I wouldn't loose sleep over using Thread.Sleep in a simple console app like this, or alternatively using something like Console.ReadLine like Neos07 suggests.
Thread.Sleep does still work, but you can consider using Task.Delay as an alternative here, like
await Task.Delay(1000);
What is the right way to execute a Time based event in C# Console App.
Example Code:
namespace ServerTools
{
public class SaveWorld
{
public static int DelayBetweenWorldSaves = 15;
public static bool IsEnabled = false;
public static Thread th;
public static bool IsRunning = false;
public static void Init()
{
if (IsEnabled && !IsRunning)
{
IsRunning = true;
StartSave();
}
}
private static void StartSave()
{
th = new Thread(new ThreadStart(Save));
th.IsBackground = true;
th.Start();
}
private static void Save()
{
while (IsEnabled)
{
int _playerCount = ConnectionManager.Instance.ClientCount();
if (_playerCount > 0)
{
List<ClientInfo> _cInfoList = ConnectionManager.Instance.GetClients();
ClientInfo _cInfo = _cInfoList.RandomObject();
SdtdConsole.Instance.ExecuteSync("saveworld", _cInfo);
Log.Out("[SERVERTOOLS] World Saved.");
}
Thread.Sleep(60000 * DelayBetweenWorldSaves);
}
}
}
}
They used Threading for this here. But isn't it a lot better to use the timers Event?
public class Timer1
{
private static System.Timers.Timer aTimer;
public static void Main()
{
// Normally, the timer is declared at the class level,
// so that it stays in scope as long as it is needed.
// If the timer is declared in a long-running method,
// KeepAlive must be used to prevent the JIT compiler
// from allowing aggressive garbage collection to occur
// before the method ends. You can experiment with this
// by commenting out the class-level declaration and
// uncommenting the declaration below; then uncomment
// the GC.KeepAlive(aTimer) at the end of the method.
//System.Timers.Timer aTimer;
// Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
// If the timer is declared in a long-running method, use
// KeepAlive to prevent garbage collection from occurring
// before the method ends.
//GC.KeepAlive(aTimer);
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}
/* This code example produces output similar to the following:
Press the Enter key to exit the program.
The Elapsed event was raised at 5/20/2007 8:42:27 PM
The Elapsed event was raised at 5/20/2007 8:42:29 PM
The Elapsed event was raised at 5/20/2007 8:42:31 PM
...
*/
I want to learn it the right way.
Also what would be the way to go if you would have to run different function on different times. Like some event runs 30 Sec the other 90 sec? Is there also something in Net which lets you execute Net Function like a Cronjob?
Thank you
here is the class:
public class Ticker
{
public event EventHandler Tick;
public EventArgs e = null;
public void TickIt()
{
while (true)
{
System.Threading.Thread.Sleep(300);
if (Tick != null)
{
Tick(this, e);
}
}
}
I'm running two threads in the windows form:
public partial class Form1 : Form
{
Ticker ticker1 = new Ticker();
Ticker ticker2 = new Ticker();
Thread t;
Thread t1;
public Form1()
{
InitializeComponent();
ticker1.Tick += ticker1_Tick;
ticker2.Tick += ticker2_Tick;
t = new Thread(new ThreadStart(ticker1.TickIt));
t1 = new Thread(new ThreadStart(ticker2.TickIt)));
t.Start();
t1.Start();
}
public void ticker1_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
ticker1_Tick(sender, e);
});
return;
}
richTextBox1.Text += "t1 ";
}
public void ticker2_Tick(object sender, EventArgs e)
{
if (this.InvokeRequired)
{
this.BeginInvoke((MethodInvoker)delegate
{
ticker2_Tick(sender, e);
});
return;
}
richTextBox2.Text += "t2 ";
}
The problem is after some seconds thread t is ahead of t1 by several ticks.
First of all why is this happening, it doesn't make sense, since each thread should wait 300 ms before ticking?
Second, how can I sync these two threads, so they tick simultaneously and one doesn't get ahead of the other?
I can't put a lock before the while loop, then only one thread will be running, while the other is locked out. Putting a lock elsewhere doesn't change anything.
If you really need them to be perfectly in synch and execute the ticks in a certain order, you will need some kind of central timer as Jaime mentioned. If you need independent timing but want to prevent drift caused by Sleep being imprecise, or delay added by the time it takes to execute the event handler, something like this would work:
public class Ticker
{
public event EventHandler Tick;
public EventArgs e = null;
public void TickIt()
{
const int targetSleepTime = 300;
int nextTick = Environment.TickCount + targetSleepTime;
while (true)
{
System.Threading.Thread.Sleep(Math.Max(nextTick - Environment.TickCount, 0));
if (Tick != null)
{
Tick(this, e);
}
nextTick += targetSleepTime;
}
}
}
Just keep in mind Environment.TickCount can wrap back to Int32.MinValue when it gets to Int32.MaxValue. You'll need extra code to handle that, or maybe base the timing on DateTime.UtcNow (less overhead than DateTime.Now).
I don't think you can trust the sleep(300) to keep your threads running the same number of times independently...
One thing you could do is to have a central timer/tick generator that signals a synchronization object on each tick, and the thread function only ticks once and then WaitsForObject for the next tick to be generated from the main thread, effectively having one timer and telling the threads to tick synchronously.
Also note that the way you are subscribing to the thread function event, you need to consider race conditions in your handler functions. Each method will run on it's own thread (until the begininvoke) so, if you access any resource (class fields etc.) those would need to be synchronized. It's just too easy to forget what's going on with the threads. :(
How about using AutoResetEvent?
class Program
{
static readonly AutoResetEvent thread1Step = new AutoResetEvent(false);
static readonly AutoResetEvent thread2Step = new AutoResetEvent(false);
static void Main(string[] args)
{
new Thread(new ThreadStart(Thread1Main)).Start();
new Thread(new ThreadStart(Thread2Main)).Start();
}
private static void Thread1Main()
{
for (int i = 0; i < int.MaxValue; i++)
{
Console.WriteLine("thread1 i=" + i);
thread1Step.Set();
thread2Step.WaitOne();
}
}
private static void Thread2Main()
{
for (int i = 0; i < int.MaxValue; i++)
{
Console.WriteLine("thread2 i=" + i);
thread2Step.Set();
thread1Step.WaitOne();
}
}
}
Well you could use a Barrier if you're using .NET 4.0, but you would have to put it in your Ticker class otherwise you'll block your UI thread.
http://msdn.microsoft.com/en-us/library/system.threading.barrier.aspx
In your Ticker class, increase your polling frequency and check the system timer until you hit the interval you're looking for. You can use TickCount or Ticks if you can live with millisecond precision, or use StopWatch for higher precision if your system supports it.
To keep them synchronized, they'll need a common reference for a start-time. You can pass this in as a specific future tick to start syncing on or use something like Tick modulus 100. Or poll for a shared static flag that signifies when to start.
You cannot have absolute precision, so define what precision range you can live with from the outset, such as plus-or-minus 5ms between your Ticker threads.
One thing that'll help is to start a shared static StopWatch instance and echo its elapsed time in all of your logging to help you characterize any delays in your app.
I'm writing a Windows service that runs a variable length activity at intervals (a database scan and update). I need this task to run frequently, but the code to handle isn't safe to run multiple times concurrently.
How can I most simply set up a timer to run the task every 30 seconds while never overlapping executions? (I'm assuming System.Threading.Timer is the correct timer for this job, but could be mistaken).
You could do it with a Timer, but you would need to have some form of locking on your database scan and update. A simple lock to synchronize may be enough to prevent multiple runs from occurring.
That being said, it might be better to start a timer AFTER your operation is complete, and just use it one time, then stop it. Restart it after your next operation. This would give you 30 seconds (or N seconds) between events, with no chance of overlaps, and no locking.
Example :
System.Threading.Timer timer = null;
timer = new System.Threading.Timer((g) =>
{
Console.WriteLine(1); //do whatever
timer.Change(5000, Timeout.Infinite);
}, null, 0, Timeout.Infinite);
Work immediately .....Finish...wait 5 sec....Work immediately .....Finish...wait 5 sec....
I'd use Monitor.TryEnter in your elapsed code:
if (Monitor.TryEnter(lockobj))
{
try
{
// we got the lock, do your work
}
finally
{
Monitor.Exit(lockobj);
}
}
else
{
// another elapsed has the lock
}
I prefer System.Threading.Timer for things like this, because I don't have to go through the event handling mechanism:
Timer UpdateTimer = new Timer(UpdateCallback, null, 30000, 30000);
object updateLock = new object();
void UpdateCallback(object state)
{
if (Monitor.TryEnter(updateLock))
{
try
{
// do stuff here
}
finally
{
Monitor.Exit(updateLock);
}
}
else
{
// previous timer tick took too long.
// so do nothing this time through.
}
}
You can eliminate the need for the lock by making the timer a one-shot and re-starting it after every update:
// Initialize timer as a one-shot
Timer UpdateTimer = new Timer(UpdateCallback, null, 30000, Timeout.Infinite);
void UpdateCallback(object state)
{
// do stuff here
// re-enable the timer
UpdateTimer.Change(30000, Timeout.Infinite);
}
instead of locking (which could cause all of your timed scans to wait and eventually stack up). You could start the scan/update in a thread and then just do a check to see if the thread is still alive.
Thread updateDBThread = new Thread(MyUpdateMethod);
...
private void timer_Elapsed(object sender, ElapsedEventArgs e)
{
if(!updateDBThread.IsAlive)
updateDBThread.Start();
}
Starting from .NET 6 there is a new timer available, the PeriodicTimer. This is a lightweight async-enabled timer, that becomes the perfect tool when overlapping executions should be strictly forbidden. You use this timer by writing an asynchronous method with a loop, and invoking it to start the loop:
private Task _operation;
private CancellationTokenSource _operationCancellation = new();
//...
_operation = StartTimer();
//...
private async Task StartTimer()
{
PeriodicTimer timer = new(TimeSpan.FromSeconds(30));
while (true)
{
await timer.WaitForNextTickAsync(_operationCancellation.Token);
try
{
DoSomething();
}
catch (Exception ex)
{
_logger.LogError(ex);
}
}
}
Instead of using a CancellationTokenSource, you can also stop the loop by disposing the PeriodicTimer. In this case the await timer.WaitForNextTickAsync() will return false.
It is possible that the DoSomething will be invoked subsequently with smaller interval than 30 seconds, but it's impossible that it will be invoked in overlapping fashion, unless you start accidentally two asynchronous loops.
This timer does not support disabling and reenabling it. If you need this functionality you could look at the third-party Nito.AsyncEx.PauseTokenSource component.
In case you are targeting a .NET version earlier than .NET 6, you could look at this question for an alternative: Run async method regularly with specified interval.
You could use the AutoResetEvent as follows:
// Somewhere else in the code
using System;
using System.Threading;
// In the class or whever appropriate
static AutoResetEvent autoEvent = new AutoResetEvent(false);
void MyWorkerThread()
{
while(1)
{
// Wait for work method to signal.
if(autoEvent.WaitOne(30000, false))
{
// Signalled time to quit
return;
}
else
{
// grab a lock
// do the work
// Whatever...
}
}
}
A slightly "smarter" solution is as follow in pseudo-code:
using System;
using System.Diagnostics;
using System.Threading;
// In the class or whever appropriate
static AutoResetEvent autoEvent = new AutoResetEvent(false);
void MyWorkerThread()
{
Stopwatch stopWatch = new Stopwatch();
TimeSpan Second30 = new TimeSpan(0,0,30);
TimeSpan SecondsZero = new TimeSpan(0);
TimeSpan waitTime = Second30 - SecondsZero;
TimeSpan interval;
while(1)
{
// Wait for work method to signal.
if(autoEvent.WaitOne(waitTime, false))
{
// Signalled time to quit
return;
}
else
{
stopWatch.Start();
// grab a lock
// do the work
// Whatever...
stopwatch.stop();
interval = stopwatch.Elapsed;
if (interval < Seconds30)
{
waitTime = Seconds30 - interval;
}
else
{
waitTime = SecondsZero;
}
}
}
}
Either of these has the advantage that you can shutdown the thread, just by signaling the event.
Edit
I should add, that this code makes the assumption that you only have one of these MyWorkerThreads() running, otherwise they would run concurrently.
I've used a mutex when I've wanted single execution:
private void OnMsgTimer(object sender, ElapsedEventArgs args)
{
// mutex creates a single instance in this application
bool wasMutexCreatedNew = false;
using(Mutex onlyOne = new Mutex(true, GetMutexName(), out wasMutexCreatedNew))
{
if (wasMutexCreatedNew)
{
try
{
//<your code here>
}
finally
{
onlyOne.ReleaseMutex();
}
}
}
}
Sorry I'm so late...You will need to provide the mutex name as part of the GetMutexName() method call.