Here I have a code of an alarm clock:
public static void Main(string[] args)
{
Console.Write("Seconds: ");
int seconds = int.Parse(Console.ReadLine());
System.Threading.Thread.Sleep(seconds * 1000);
Timer timer = new Timer(100);
timer.Elapsed += MakeSound;
timer.Enabled = true;
GC.KeepAlive(timer);
Console.ReadLine();
}
private static void MakeSound(object sender, ElapsedEventArgs e)
{
Console.Beep();
}
As you can see, it doesn't look so promising because I am using Thread.Sleep.
It still works if I use
Timer timer = new Timer(seconds * 1000); instead of System.Threading.Thread.Sleep(seconds * 1000);
But it doesn't beep constantly, just between interval of seconds * 1000 seconds until user presses Enter. Can I make it any better?
If you look at the constructor overloads for System.Threading.Timer, you'll see that you can specify the dueTime, as well as the period: https://msdn.microsoft.com/en-us/library/2x96zfy7(v=vs.110).aspx
So, instead of using System.Threading.Thread.Sleep(1000 * seconds), use
Timer timer = new Timer(new TimerCallback(MakeSound), null, 1000 * seconds, 100);
Related
I'm trying to create a timed task program (think Reminders app for Apple but with timers), and I'm trying to implement the timer. The timer starts and the event works fine, but for some reason, the timer event gets called right after starting the timer, rather than after the specified interval. This is my code for setting the interval:
newTask.timerTime = float.Parse(timeInput.Text);
newTask.Initialize();
switch (timeInput.Text)
{
case "Seconds":
newTask.timer.Interval = (int)newTask.timerTime * 1000;
break;
case "Minutes":
newTask.timer.Interval = (int)(newTask.timerTime * 1000) * 60;
break;
case "Hours":
newTask.timer.Interval = (int)((newTask.timerTime * 1000) * 60) * 60;
break;
}
newTask.timer.Enabled = true;
newTask.timer.Start();
And this is my code for creating the event (and Timer.Tick):
public void Initialize()
{
timer.Tick += new System.EventHandler(OnTimerEnd);
}
//Timer event
private void OnTimerEnd(object sender, EventArgs e)
{
new ToastContentBuilder()
.AddArgument("action", "viewConversation")
.AddArgument("taskid", 1)
.AddText("Your timer is up!")
.AddText($#"Your task, {taskName}, is now completed! Great job!")
.Show();
timer.Stop();
timer.Enabled = false;
}
I have a method which does some calculations.
public void CalculateItems()
{
// Calculate the empty Items
}
Which I need to execute in every 30th second of a minute.
If my service starts at 10:00:15, The method should start working from 10:00:30, 10:01:00, 10:01:30 and goes on.
If my Service starts at 10:00:50, The method should start working from 10:01:00, 10:01:30, 10:02:00 and goes on.
I have tried System.Threading.Timer, System.Timers.Timer but in all these, I couldn't achieve my scenario. Please help with your valuable suggestions.
What I have tried is in System.Threading.Timer
var timer = new System.Threading.Timer(
e => CalculateItems(),
null,
TimeSpan.Zero,
TimeSpan.FromSeconds(30));
But it hits my method every 30th second Not in 30th second of every minute
One simple way to solve it using a timer is to set the interval to a single second, and in the timer's callback method to check if the value of DateTime.Now.Seconds divides by 30:
void Timer_Elapsed(object sender, ElapsedEventArgs e)
{
if(DateTime.Now.Seconds % 30 == 0)
{
CalculateItems();
}
}
You can initially start the timer with 1 second interval. Then in the Timer Event, if DateTime.Now.Second is 30 or 0, You can set the interval to 30 seconds. From then on your event would be triggered only at specified time.
System.Timers.Timer timer= new System.Timers.Timer(1000);
private void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
{
if(timer.Interval!=30000 && DateTime.Now.Seconds % 30 == 0)
{
timer.Stop();
timer.Interval = 30000;
timer.Start();
DoWork();
}
else
{
if(timer.Interval==30000)
{
DoWork();
}
}
}
I solved it with timers, and calculating the sime to the next 30 sec block:
It is recalculating the 30 sec again after elapsed, otherwise it will slightly get a delta after each run.
class Program
{
static System.Threading.Timer _ttimer;
static void Main(string[] args)
{
SetupTimerTo30sec();
Console.ReadLine();
}
private static void SetupTimerTo30sec()
{
var now = DateTime.Now;
int diffMilliseconds;
if (now.Second < 30)
{
diffMilliseconds = (30 - now.Second) * 1000;
}
else
{
diffMilliseconds = (60 - now.Second) * 1000;
}
diffMilliseconds -= now.Millisecond;
if (_ttimer != null)
{
_ttimer.Change(diffMilliseconds, 30 * 1000);
}
else
{
_ttimer = new Timer(OnElapsed, null, diffMilliseconds, 30 * 1000);
}
}
private static void OnElapsed(object state)
{
Console.Write(DateTime.Now.ToLongTimeString());
Console.WriteLine($":{DateTime.Now.Millisecond}");
SetupTimerTo30sec();
}
}
i want to segue to a new View Controller when the countdown timer, here set to 10 seconds, reaches 0 seconds. it does this using the thread logic below. the label usually shows the countdown "10, 9, 8, 7" but since i used ViewDidAppear, it doesnt show. at the end itll flash 0 seconds, and the segue will take place. i need the countdown to show the whole time, and cant figure out how and why its dissapearing
using System.Timers;
using System.Threading;
...
private System.Timers.Timer mytimer;
private int countSeconds;
...
public override void ViewDidLoad()
{
base.ViewDidLoad();
mytimer = new System.Timers.Timer();
//Trigger event every second
mytimer.Interval = 1000; //1000 = 1 second
mytimer.Elapsed += OnTimedEvent;
countSeconds = 10; // 300 seconds
mytimer.Enabled = true;
mytimer.Start();
}
private void OnTimedEvent(object sender, ElapsedEventArgs e)
{
countSeconds--;
int seconds = countSeconds % 60;
int minutes = countSeconds / 60;
string DHCountdownTime = (countSeconds / 60).ToString() + ":" + (countSeconds % 60).ToString("00"); //to give leading 0. so 9 seconds isnt :9 but :09
InvokeOnMainThread(() =>
{
lblTimer.Text = DHCountdownTime;
});
if (countSeconds == 0)
{
mytimer.Stop();
}
}
...
public override void ViewDidAppear(bool animated)
{
base.ViewDidAppear(animated);
Thread.Sleep(countSeconds * 1000);
PerformSegue("DHSegue", this);
...
Your Thread.Sleep is blocking the UI thread:
Thread.Sleep(countSeconds * 1000);
Use a task (or another thread) in order allow the UI thread to continue to process messages:
await Task.Delay(countSeconds * 1000);
I want to execute a method every hour on the hour. I wrote some code,but it is not enough for my aim. Below code is working every 60 minutes.
public void Start()
{
System.Threading.Timer timerTemaUserBilgileri = new System.Threading.Timer(new System.Threading.TimerCallback(RunTakip), null, tmrTemaUserBilgileri, 0);
}
public void RunTakip(object temauserID)
{
try
{
string objID = "6143566557387";
EssentialMethod(objID);
TimeSpan span = DateTime.Now.Subtract(lastRunTime);
if (span.Minutes > 60)
{
tmrTemaUserBilgileri = 1 * 1000;
timerTemaUserBilgileri.Change(tmrTemaUserBilgileri, 0);
}
else
{
tmrTemaUserBilgileri = (60 - span.Minutes) * 60 * 1000;
timerTemaUserBilgileri.Change(tmrTemaUserBilgileri, 0);
}
watch.Stop();
var elapsedMs = watch.ElapsedMilliseconds;
}
catch (Exception ex)
{
timerTemaUserBilgileri.Change(30 * 60 * 1000, 0);
Utils.LogYaz(ex.Message.ToString());
}
}
public void EssentialMethod(objec obj)
{
//some code
lastRunTime = DateTime.Now;
//send lastruntime to sql
}
If you want your code to be executed every 60 minutes:
aTimer = new System.Timers.Timer(60 * 60 * 1000); //one hour in milliseconds
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Start();
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
//Do the stuff you want to be done every hour;
}
if you want your code to be executed every hour (i.e. 1:00, 2:00, 3:00) you can create a timer with some small interval (let's say a second, depends on precision you need) and inside that timer event check if an hour has passed
aTimer = new System.Timers.Timer(1000); //One second, (use less to add precision, use more to consume less processor time
int lastHour = DateTime.Now.Hour;
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
aTimer.Start();
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
if(lastHour < DateTime.Now.Hour || (lastHour == 23 && DateTime.Now.Hour == 0))
{
lastHour = DateTime.Now.Hour;
YourImportantMethod(); // Call The method with your important staff..
}
}
I agree with SeƱor Salt that the chron job should be the first choice. However, the OP asked for every hour on the hour from c#. To do that, I set up the first timed event to fire on the hour:
int MilliSecondsLeftTilTheHour()
{
int interval;
int minutesRemaining = 59 - DateTime.Now.Minute;
int secondsRemaining = 59 - DateTime.Now.Second;
interval = ((minutesRemaining * 60) + secondsRemaining) * 1000;
// If we happen to be exactly on the hour...
if (interval == 0)
{
interval = 60 * 60 * 1000;
}
return interval;
}
Timer timer = new Timer();
timer.Tick += timer_Tick;
timer.Enabled = true;
timer.Interval = MilliSecondsLeftTilTheHour();
The problem now is that if the above timer.Interval happens to be 45 minutes and 32 seconds, then the timer will continue firing every 45:32 not just the first time. So, inside the timer_Tick method, you have to readjust the timer.Interval to one hour.
void timer_Tick(object sender, EventArgs e)
{
// The Interval could be hard wired here to 60 * 60 * 1000 but on clock
// resets and if the job ever goes longer than an hour, why not
// recalculate once an hour to get back on track.
timer.Interval = MilliSecondsLeftTilTheHour();
DoYourThing();
}
Just a small comment based on /Anarion's solution that I couldn't fit into a comment.
you can create a timer with some small interval (let's say a second, depends on precision you need)
You don't need it to go with any precision at all, you're thinking "how do I check this hour is the hour I want to fire". You could alternatively think "How do I check the next hour is the hour I want to fire" - once you think like that you realise you don't need any precision at all, just tick once an hour, and set a thread for the next hour. If you tick once an hour you know you'll be at some point before the next hour.
Dim dueTime As New DateTime(Date.Today.Year, Date.Today.Month, Date.Today.Day, DateTime.Now.Hour + 1, 0, 0)
Dim timeRemaining As TimeSpan = dueTime.Subtract(DateTime.Now)
t = New System.Threading.Timer(New System.Threading.TimerCallback(AddressOf Method), Nothing, CType(timeRemaining.TotalMilliseconds, Integer), System.Threading.Timeout.Infinite)
How about something simpler? Use a one-minute timer to check the hour:
public partial class Form1 : Form
{
int hour;
public Form1()
{
InitializeComponent();
if(RunOnStartUp)
hour = -1;
else
hour = DateTime.Now.Hour;
}
private void timer1_Tick(object sender, EventArgs e)
{
// once per minute:
if(DateTime.Now.Hour != hour)
{
hour = DateTime.Now.Hour;
DailyTask();
}
}
private DailyTask()
{
// do something
}
}
Use a Cron Job on the server to call a function at the specified interval
Heres a link
http://www.thesitewizard.com/general/set-cron-job.shtml
What about trying the below code, the loop is determined to save your resources, and it is running every EXACT hour, i.e. with both minutes and seconds (and almost milliseconds equal to zero:
using System;
using System.Threading.Tasks;
namespace COREserver{
public static partial class COREtasks{ // partial to be able to split the same class in multiple files
public static async void RunHourlyTasks(params Action[] tasks)
{
DateTime runHour = DateTime.Now.AddHours(1.0);
TimeSpan ts = new TimeSpan(runHour.Hour, 0, 0);
runHour = runHour.Date + ts;
Console.WriteLine("next run will be at: {0} and current hour is: {1}", runHour, DateTime.Now);
while (true)
{
TimeSpan duration = runHour.Subtract(DateTime.Now);
if(duration.TotalMilliseconds <= 0.0)
{
Parallel.Invoke(tasks);
Console.WriteLine("It is the run time as shown before to be: {0} confirmed with system time, that is: {1}", runHour, DateTime.Now);
runHour = DateTime.Now.AddHours(1.0);
Console.WriteLine("next run will be at: {0} and current hour is: {1}", runHour, DateTime.Now);
continue;
}
int delay = (int)(duration.TotalMilliseconds / 2);
await Task.Delay(30000); // 30 seconds
}
}
}
}
Why is everyone trying to handle this problem with a timer?
you're doing two things... waiting until the top of the hour and then running your timer every hour on the hour.
I have a windows service where I needed this same solution. I did my code in a very verbose way so that it is easy to follow for anyone. I know there are many shortcuts that can be implemented, but I leave that up to you.
private readonly Timer _timer;
/// starts timer
internal void Start()
{
int waitTime = calculateSleepTime();
System.Threading.Thread.Sleep(waitTime);
object t = new object();
EventArgs e = new EventArgs();
CheckEvents(t, e);
_timer.Start();
}
/// runs business logic everytime timer goes off
internal void CheckEvents(object sender, EventArgs e)
{
// do your logic here
}
/// Calculates how long to wait until the top of the hour
private int calculateSleepTime()
{
DateTime now = DateTime.Now;
int minutes = now.Minute * 60 * 1000;
int seconds = now.Second * 1000;
int substrahend = now.Millisecond + seconds + minutes;
int minuend = 60 * 60 * 1000;
return minuend - substrahend;
}
Here's a simple, stable (self-synchronizing) solution:
while(true) {
DoStuff();
var now = DateTime.UtcNow;
var previousTrigger = new DateTime(now.Year, now.Month, now.Day, now.Hour, 0, 0, now.Kind);
var nextTrigger = previousTrigger + TimeSpan.FromHours(1);
Thread.Sleep(nextTrigger - now);
}
Note that iterations may be skipped if DoStuff() takes longer than an hour to execute.
I have 5 methods and I need them to be called after random interval(1 to 3 sec) of time. Say first method is called after 1 sec, then second method is called after 2.3 sec, next method after 1.5 etc. I did following using timer
Random rand = new Random();
fortimerinterval1 = rand.Next(1000, 3000);
mytimer1.Interval = fortimerinterval1;
mytimer1.Enabled = true;
mytimer1.Start();
But the problem is, timer interval do not change everytime. Timer interval remain constant after first time. How to make it random so that each time timer interval change.
Do something like this
Random rand = new Random();
Timer mytimer = new Timer();
private void button1_Click(object sender, EventArgs e)
{
mytimer.Tick += new EventHandler(TimerEventProcessor);
int fortimerinterval = rand.Next(1000, 3000);
mytimer.Interval = fortimerinterval;
mytimer.Enabled = true;
mytimer.Start();
}
public void TimerEventProcessor(Object myObject, EventArgs myEventArgs)
{
int fortimerinterval = rand.Next(1000, 3000);
mytimer.Interval = fortimerinterval;
System.Diagnostics.Debug.WriteLine(DateTime.Now);
}
Set the interval in your timer elapsed method.
Random rand = new Random();
private void OnTick(object sender, EventArgs eventArgs)
{
_timer.Interval = rand.Next(1000, 3000);
}
Watch out for overlapped callbacks if you use System.Timers.Timer. For example, if the first tick fires after 1 second and the method that you call in the tick callback takes longer than 1 second to complete, you'll end up with another tick callback being called 1 second after the first, before you change the interval.
I would use a System.Threading.Timer configured to fire once and in the callback method change it to fire again at the next random interval.
Like this:
public TestClass()
{
_random = new Random(Environment.TickCount);
_timer = new Timer(TimerCallback, null, _random.Next(1000, 3000), Timeout.Infinite);
}
private void TimerCallback(object state)
{
try
{
// Do something.
}
finally
{
_timer.Change(_random.Next(1000, 3000), Timeout.Infinite);
}
}