JS's setInterval and setTimeOut is really convenient. And I want to ask how to implement the same thing in C#.
You can just do a Task.Delay within a Task.Run, try out:
var task = Task.Run(async () => {
for(;;)
{
await Task.Delay(10000)
Console.WriteLine("Hello World after 10 seconds")
}
});
Then You could even wrap this up in to your own SetInterval method that takes in an action
class Program
{
static void Main(string[] args)
{
SetInterval(() => Console.WriteLine("Hello World"), TimeSpan.FromSeconds(2));
SetInterval(() => Console.WriteLine("Hello Stackoverflow"), TimeSpan.FromSeconds(4));
Thread.Sleep(TimeSpan.FromMinutes(1));
}
public static async Task SetInterval(Action action, TimeSpan timeout)
{
await Task.Delay(timeout).ConfigureAwait(false);
action();
SetInterval(action, timeout);
}
}
or you could just use the built in Timer class which practically does the same thing
static void Main(string[] args)
{
var timer1 = new Timer(_ => Console.WriteLine("Hello World"), null, 0, 2000);
var timer2 = new Timer(_ => Console.WriteLine("Hello Stackoverflow"), null, 0, 4000);
Thread.Sleep(TimeSpan.FromMinutes(1));
}
Just make sure you're timers don't go out of scope and get disposed.
.NET 6 Update
.NET 6 introduced a new type called PeriodicTimer this simplifies the above, and can be used like the following:
var timer = new PeriodicTimer(TimeSpan.FromSeconds(10));
while (await timer.WaitForNextTickAsync())
{
Console.WriteLine("Hello World after 10 seconds")
}
If you need to be able to cancel the timer the WaitForNextTickAsync function has an overload for
a cancellation token.
Its simply like this, you define an static System.Timers.Timer; then call the function that binds the timer.Elapsed event to your interval function that will be called each X miliseconds.
public class StaticCache {
private static System.Timers.Timer syncTimer;
StaticCache(){
SetSyncTimer();
}
private void SetSyncTimer(){
// Create a timer with a five second interval.
syncTimer = new System.Timers.Timer(5000);
// Hook up the Elapsed event for the timer.
syncTimer.Elapsed += SynchronizeCache;
syncTimer.AutoReset = true;
syncTimer.Enabled = true;
}
private static void SynchronizeCache(Object source, ElapsedEventArgs e)
{
// do this stuff each 5 seconds
}
}
Related
I'm currently trying to implement a real-time multithreading software in C#. I need 3 threads. Every thread execution has to be finished before a deadline (500µs / 100µs / 50µs). The threads must run parallel during the whole runtime (until the user shuts down the program).
Is there a mecanism that can guarantee that the thread execution will not pass the deadline?
Here is my code :
static void Main(string[] args)
{
Thread thread1 = new Thread(FirstThread);
Thread thread2 = new Thread(SecondThread);
Thread thread3 = new Thread(ThirdThread);
thread1.start();
thread2.start();
thread3.start();
}
static void FirstThread()
{
while(true)
{
SleepMicroSec(500);
}
}
static void SecondThread()
{
while(true)
{
SleepMicroSec(100);
}
}
static void ThirdThread()
{
while(true)
{
SleepMicroSec(50);
}
}
private static void SleepMicroSec(long microSec)
{
var sw = Stopwatch.StartNew();
while (sw.ElapsedTicks / (Stopwatch.Frequency / (1000L * 1000L)) < microSec)
{
}
}
I expect the scheduler to be able to perform the context switching if the Task deadline is reached.
Thanks in advance for your answers !
Here is a method that invokes repeatedly an action in a background thread, aborting and restarting the thread every time the deadline is passed. It also accepts a CancellationToken to allow for premature cancellation of the procedure (before the end of the program).
private static void RepeatInBackgroundThread(Action action, int timeout,
CancellationToken cancellationToken)
{
var timer = new System.Timers.Timer(timeout);
timer.AutoReset = false; // to raise the Elapsed event only once
var thread = new Thread(() =>
{
while (true)
{
if (cancellationToken.IsCancellationRequested) return;
timer.Start();
action();
timer.Stop();
}
});
timer.Elapsed += (sender, e) =>
{
thread.Abort();
thread.Join(); // Wait for the thread to die
if (cancellationToken.IsCancellationRequested) return;
RepeatInBackgroundThread(action, timeout, cancellationToken);
};
thread.IsBackground = true;
thread.Start();
}
Usage example:
var random = new ThreadLocal<Random>(() => new Random());
var cts = new CancellationTokenSource();
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 1000)), 500, cts.Token);
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 200)), 100, cts.Token);
RepeatInBackgroundThread(() => Thread.Sleep(random.Value.Next(0, 100)), 50, cts.Token);
//cts.CancelAfter(10000);
It should be noted that aborting threads is not a good practice in general.
I have seen plenty of examples (here and elsewhere) of creating a non-reentrant timer by stopping the timer when the elapsed handler method is called and starting it again at the end of the elapsed handler method. This seems to be the recommended approach. The problem with this approach is that you will have a gap in time while the Elapsed Handler Method is running. You could end up with timing that is off by quite a lot within a short period of time.
So I was thinking about a better approach and I can up with the idea to use a bool to determine the state of the Timer, and whether the Elapsed Handler is currently running or not, it is is running then the call to the Elapsed Handler is returned immediately and the rest is not executed.
Below is the basic Idea
volatile bool _IsProcessingElapsedMethod = false;
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_IsProcessingElapsedMethod)
{
Console.WriteLine("Warning: Re-Entrance was attempted and Ignored.");
return;
}
_IsProcessingElapsedMethod = true;
//** DO Something here
_IsProcessingElapsedMethod = false;
}
There has to be a reason I have never seen anyone do this. Am I missing some obvious Gotcha? It seems like a pretty easy solution.
Below is a compilable example.
using System;
using System.Threading.Tasks;
using System.Timers;
namespace QuestionNon_ReEntrantTimer
{
class Program
{
static private int Timer1_ElapsedCount = 1;
static void Main(string[] args)
{
NonReEntrantTimer timer1 = new NonReEntrantTimer(500);
timer1.Elapsed += Timer1_Elapsed;
timer1.Start();
Console.WriteLine("Press Any key to Exit");
Console.ReadKey();
}
private static void Timer1_Elapsed(object sender, ElapsedEventArgs e)
{
int delayTime;
if(Timer1_ElapsedCount < 10)
{
delayTime = 300 * Timer1_ElapsedCount++;
}
else
{
Timer1_ElapsedCount++;
delayTime = 400;
}
Console.WriteLine($"Timer1_Elapsed Call Count is {Timer1_ElapsedCount} Waiting for {delayTime} ms");
Task.Delay(delayTime).Wait();
}
}
public class NonReEntrantTimer : IDisposable
{
Timer _timer = new Timer();
public event ElapsedEventHandler Elapsed;
volatile bool _IsProcessingElapsedMethod = false;
public NonReEntrantTimer(double interval)
{
_timer = new Timer(interval);
_timer.Elapsed += _timer_Elapsed;
}
public void Start() => _timer.Start();
public void Stop() => _timer.Stop();
public void Close() => _timer.Close();
private void _timer_Elapsed(object sender, ElapsedEventArgs e)
{
if (_IsProcessingElapsedMethod)
{
Console.WriteLine("Warning: Re-Entrance was attempted and Ignored.");
return;
}
_IsProcessingElapsedMethod = true;
Elapsed?.Invoke(sender, e);
_IsProcessingElapsedMethod = false;
}
public void Dispose()
{
_timer.Dispose();
}
}
}
I would propose this simple async pattern. It executes the given Action every ts, but starts countdown to the next execution before starting the current iteration. If the execution takes more time than ts, the next iteration is postponed till after the previous one finishes.
async Task ExecuteEvery(TimeSpan ts, Action a, CancellationToken ct)
{
try
{
var currentDelay = Task.Delay(ts, ct);
while (!ct.IsCancellationRequested)
{
await currentDelay; // waiting for the timeout
currentDelay = Task.Delay(ts, ct); // timeout finished, starting next wait
a(); // executing action in the meanwhile
}
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
// if we are cancelled, nothing to do, just exit
}
}
You can stop the iterations by cancelling the token. You can offload the action execution to the thread pool by starting the operation with Task.Run.
Update: if you want the timer to try catching up after the slow action, you can do it with some minor changes:
async Task ExecuteEvery(TimeSpan ts, Action a, CancellationToken ct)
{
try
{
for (var targetTime = DateTime.Now + ts; !ct.IsCancellationRequested; targetTime += ts)
{
var timeToWait = targetTime - DateTime.Now;
if (timeToWait > TimeSpan.Zero)
await Task.Delay(timeToWait, ct);
a();
}
}
catch (OperationCanceledException) when (ct.IsCancellationRequested)
{
// if we are cancelled, nothing to do, just exit
}
}
I'm having issues creating a timer that when started will first sleep for 2 minutes. It will run for 5 minutes total and every minute will do work. This is what I have:
class Program{
static System.Timers.Timer aTimer;
static System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
static TimeSpan LongToRun = new TimeSpan(0,300,0)); //run for 5 minutes
static void Main (string[] args){
Thread.Sleep(120000); //sleep for 2 mins
sw.Reset();
sw.Start();
Start();
}
static void Start()
{
aTimer = new System.Timers.Timer();
aTimer.Interval = 60000; //every min
aTimer.Enabled = true;
aTimer.Elapsed += new ElapsedEventHandler(timer_Elapsed);
aTimer.Start();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
TimeSpan ts = sw.Elapsed;
if (ts.TotalSeconds >= LongToRun.TotalSeconds)
{
aTimer.Stop();
return;
}
DoWork();
}
}
timer_Elapsed never is called... Am I going about this wrong?
Your Start procedure returns immediately after it started the timer and returns to your main program. The main program ends and the timer that was still running is finalized before it elapses.
Solution: make sure your program is running long enough for your timer to elapse.
The main program creates a System.Threading.ManualResetEvent before starting the timer
After starting the timer it waits for the ManualResetEvent to be set using ManualResetEvent.WaitOne()
At the end of your timer_elapsed function the function raises the event using ManualResetEvent.Set
The thread in the main program that waited for this event continues processing.
Another problem is that you subscribe to the event after you started your timer. This is probably not a cause of the problem, but neat code would be to subscribe before you start the timer.
By the way, the timer class implements IDisposable. This means that the designer of this class informs you he uses scarce resources that need to be freed as soon as possible. Consider Disposing the Timer class as soon as it is not needed anymore. The using (...) statement is ideal for this.
Using async-await would make your code much easier to read and to maintain.
Consider the following code:
public static void Main()
{
Thread.Sleep(TimeSpan.FromMinutes(2));
var myTask = Task.Run( () => WorkerTask())
Task.Wait(myTask);
}
private static TimeSpan longToRun = new TimeSpan.FromMinutes(5);
// easier to read than new TimeSpan(0,300,0));
public static async Task WorkerTask()
{
StopTime = DateTime.Now + longToRun;
// repeatedly wait a while and DoWork():
while (DateTime.Now < StopTime)
{
await Task.Delay(TimeSpan.FromMinutes(2);
DoWork();
}
}
That's all, No need for ManualResetEvents, no Stopwatches, no Timers nor timer_elapsed event handlers.
It is even quite easy to pass parameters to procedure WorkerTask(), and cancelling the event for instance because the operator presses < esc > is easy if you create a CancellationTokenSource and pass a CancellationToken to the WorkerTask as a parameter. In fact, that would make the code even more simpler:
public static void Main()
{
Thread.Sleep(TimeSpan.FromMinutes(2));
using (var tokenSource = new CancellationTokenSource())
{
var myTask = Task.Run( () => WorkerTask(tokenSource.Token))
tokenSource.CancelAfter(TimerSpan.FromMinutes(5));
// instead of LongToRun
Task.Wait(myTask);
}
}
public static async Task WorkerTask(CancellationToken token)
{
// repeatedly wait a while and DoWork():
while (!token.IsCancellationRequested)
{
await Task.Delay(TimeSpan.FromMinutes(2, token);
DoWork();
}
}
More information:
MSDN Task Cancellation
Async await explained
As Sergey pointed out there is a mistake in the time period set in Timespan LongToRun. I have tried a cod with just Thread.sleep function. Hope the code is helpful for you.
class Program {
static System.Timers.Timer aTimer;
static System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
static TimeSpan LongToRun = new TimeSpan(0,5,0); //run for 5 minutes
static void Main (string[] args) {
Console.WriteLine("Start Of Program" + DateTime.Now);
Thread.Sleep(120000); //sleep for 2 mins
sw.Reset();
sw.Start();
Start();
}
static void Start() {
TimeSpan ts = sw.Elapsed;
while (ts.TotalSeconds < LongToRun.TotalSeconds) {
doWork();
Thread.Sleep(60000);
ts = sw.Elapsed;
}
Console.WriteLine("End of program");
Console.ReadLine();
}
static void doWork() {
Console.WriteLine(DateTime.Now);
}
}
First of all, you've set incorrect period:
static TimeSpan LongToRun = new TimeSpan(0,**5**,0)); //run for 5 minutes
timer_Elapsed is never called because your application is closed earlier. Add Console.ReadLine() at the end.
static void Main (string[] args){
Thread.Sleep(120000); //sleep for 2 mins
sw.Reset();
sw.Start();
Start();
Console.ReadLine();
}
I need a method to run accurately every 5 minutes. I can't use Timer because I noticed it will slowly become out of sync (i.e. it will eventually run at 00:01, 00:06, 00:11, 00:16, and so on).
Although it needs to be accurate, I don't need it to be too precise. Every 5 minutes +/- 1 second will be okay, just as long as after days of running, it will still tick accurately on the 5 minute marks.
What I have thought of so far is creating a Timer with an Interval of 1 second that constantly checks DateTime.Now to see if the next 5 minute mark is passed. I am wondering if there is a more elegant solution or something in the C# libraries that I have missed.
Edit: I have the following template now, which is working to my requirements.
public class ThreadTest
{
private Thread thread;
private long nextExecutionTime;
private long interval;
public void StartThread(long intervalInMillis)
{
interval = intervalInMillis * TimeSpan.TicksPerMillisecond;
nextExecutionTime = DateTime.Now.Ticks;
thread = new Thread(Run);
thread.Start();
}
private void Run()
{
while (true)
{
if (DateTime.Now.Ticks >= nextExecutionTime)
{
nextExecutionTime += interval;
// do stuff
}
}
}
}
if you are not happy with Timer?
then you can try to make your thread sleep for 5 mintues, instead of using Timer
have a look this, hope it helps
using System;
using System.Threading;
public class Worker
{
// This method will be called when the thread is started.
public void DoWork()
{
while (!_shouldStop)
{
Task.Factory.Start(() =>
{
// do you task async
})
Thread.Sleep(300000);
}
}
public void DoWork2()
{
var watch = new Stopwatch();
while (!_shouldStop)
{
watch.Start();
Task.Factory.Start(() =>
{
// do you task async
})
while(watch.Elapsed.ElapsedMilliseconds < 300000);
watch.Stop();
watch.Reset();
}
}
public void RequestStop()
{
_shouldStop = true;
}
private volatile bool _shouldStop;
}
public class WorkerThreadExample
{
static void Main()
{
// Create the thread object. This does not start the thread.
Worker workerObject = new Worker();
Thread workerThread = new Thread(workerObject.DoWork);
// Start the worker thread.
workerThread.Start();
// Loop until worker thread activates.
while (!workerThread.IsAlive);
while (true)
{
//do something to make it break
}
// Request that the worker thread stop itself:
workerObject.RequestStop();
workerThread.Join();
}
}
or you can try this:
I have a Windows Forms application written in C#. The following function checks whenever printer is online or not:
public void isonline()
{
PrinterSettings settings = new PrinterSettings();
if (CheckPrinter(settings.PrinterName) == "offline")
{
pictureBox1.Image = pictureBox1.ErrorImage;
}
}
and updates the image if the printer is offline. Now, how can I execute this function isonline() every 2 seconds so when I unplug the printer, the image displayed on the form (pictureBox1) turns into another one without relaunching the application or doing a manual check? (eg. by pressing "Refresh" button which runs the isonline() function)
Use System.Windows.Forms.Timer.
private Timer timer1;
public void InitTimer()
{
timer1 = new Timer();
timer1.Tick += new EventHandler(timer1_Tick);
timer1.Interval = 2000; // in miliseconds
timer1.Start();
}
private void timer1_Tick(object sender, EventArgs e)
{
isonline();
}
You can call InitTimer() in Form1_Load().
.NET 6 has added the PeriodicTimer class.
var periodicTimer= new PeriodicTimer(TimeSpan.FromSeconds(1));
while (await periodicTimer.WaitForNextTickAsync())
{
// Place function in here..
Console.WriteLine("Printing");
}
You can run it in the background with this:
async Task RunInBackground(TimeSpan timeSpan, Action action)
{
var periodicTimer = new PeriodicTimer(timeSpan);
while (await periodicTimer.WaitForNextTickAsync())
{
action();
}
}
RunInBackground(TimeSpan.FromSeconds(1), () => Console.WriteLine("Printing"));
The main advantage PeriodicTimer has over a Timer.Delay loop is best observed when executing a slow task.
using System.Diagnostics;
var stopwatch = Stopwatch.StartNew();
// Uncomment to run this section
//while (true)
//{
// await Task.Delay(1000);
// Console.WriteLine($"Delay Time: {stopwatch.ElapsedMilliseconds}");
// await SomeLongTask();
//}
//Delay Time: 1007
//Delay Time: 2535
//Delay Time: 4062
//Delay Time: 5584
//Delay Time: 7104
var periodicTimer = new PeriodicTimer(TimeSpan.FromMilliseconds(1000));
while (await periodicTimer.WaitForNextTickAsync())
{
Console.WriteLine($"Periodic Time: {stopwatch.ElapsedMilliseconds}");
await SomeLongTask();
}
//Periodic Time: 1016
//Periodic Time: 2027
//Periodic Time: 3002
//Periodic Time: 4009
//Periodic Time: 5018
async Task SomeLongTask()
{
await Task.Delay(500);
}
PeriodicTimer will attempt to invoke every n * delay seconds, whereas Timer.Delay will invoke every n * (delay + time for method to run) seconds, causing execution time to gradually move out of sync.
The most beginner-friendly solution is:
Drag a Timer from the Toolbox, give it a Name, set your desired Interval, and set "Enabled" to True. Then double-click the Timer and Visual Studio (or whatever you are using) will write the following code for you:
private void wait_Tick(object sender, EventArgs e)
{
refreshText(); // Add the method you want to call here.
}
No need to worry about pasting it into the wrong code block or something like that.
Threaded:
/// <summary>
/// Usage: var timer = SetIntervalThread(DoThis, 1000);
/// UI Usage: BeginInvoke((Action)(() =>{ SetIntervalThread(DoThis, 1000); }));
/// </summary>
/// <returns>Returns a timer object which can be disposed.</returns>
public static System.Threading.Timer SetIntervalThread(Action Act, int Interval)
{
TimerStateManager state = new TimerStateManager();
System.Threading.Timer tmr = new System.Threading.Timer(new TimerCallback(_ => Act()), state, Interval, Interval);
state.TimerObject = tmr;
return tmr;
}
Regular
/// <summary>
/// Usage: var timer = SetInterval(DoThis, 1000);
/// UI Usage: BeginInvoke((Action)(() =>{ SetInterval(DoThis, 1000); }));
/// </summary>
/// <returns>Returns a timer object which can be stopped and disposed.</returns>
public static System.Timers.Timer SetInterval(Action Act, int Interval)
{
System.Timers.Timer tmr = new System.Timers.Timer();
tmr.Elapsed += (sender, args) => Act();
tmr.AutoReset = true;
tmr.Interval = Interval;
tmr.Start();
return tmr;
}
Things have changed a lot with time.
You can use the solution below:
static void Main(string[] args)
{
var timer = new Timer(Callback, null, 0, 2000);
//Dispose the timer
timer.Dispose();
}
static void Callback(object? state)
{
//Your code here.
}
You can do this easily by adding a Timer to your form (from the designer) and setting it's Tick-function to run your isonline-function.
using System;
using System.Timers;
namespace SnirElgabsi
{
class Program
{
private static Timer timer1;
static void Main(string[] args)
{
timer1 = new Timer(); //new Timer(1000);
timer1.Elpased += (sender,e) =>
{
MyFoo();
}
timer1.Interval = 1000;//miliseconds
timer1.Start();
Console.WriteLine("press any key to stop");
Console.ReadKey();
}
private static void MyFoo()
{
Console.WriteLine(string.Format("{0}", DateTime.Now));
}
}
}