Run method after defined time on windows service - c#

My Question is more about getting to the same destination, but there must be another way. Right now im creating a DateTime and compare that to another DateTime and check, if the time difference I set up might be right. So far so good but I just can't accept that I create a new propertie everytime the loop will get into that code.
Is there any possible way to get to the same destination, but in some kind of more effective way?
I got you guys some example code here:
private void RunService()
{
// Runs as long as the service didn't got a stop call.
while (!SetStop)
{
//Get MinutesToWait
this.MinutesToWait = 5;
DateTime CheckRunTime = this.LastRun;
CheckRunTime.AddMinutes(this.MinutesToWait);
if (DateTime.Now >= CheckRunTime)
{
// Imagine some good and smart and totally runnable code?
}
}
}

If I understood correctly, what you want to do is execute a piece of code some time after the service starts. If that is the case, then your best bet would be to use a timer.
First off, you have to convert the amount of time you want to wait to milliseconds. For example, 5 minutes equals 300000ms. Then, you have to move the code you want to execute to a separate method. I will name this method RunCode() for the example. Finally, you create your timer like so:
private void RunService()
{
var timer = new Timer(300000);
timer.Elapsed += (s, e) => this.RunCode();
timer.Start();
Thread.Sleep(Timeout.Infinite);
}
What we are doing here is the following.
Instantiating the timer with an interval of 300000ms
Subscribing to the timer's Elapsed event, which fires when the specified time has passed
Starting the timer
Sleeping our main thread forever. This line is optional. Whether you need it or not depends on the structure of your program. If nothing else happens in your code after you start the timer, the main thread and by extension the whole program will exit. However by sleeping it with an infinite timeout, we can prevent that.
If you're sure that this, delayed execution of code, is what you want, then the solution I have provided should work quite well. However I'm worried this may be an XY problem, meaning this is the solution you have come up with for a different issue which could be solved better. So I have to ask, why exactly do you need this in your service?

Use System.Timers
static void Main(string[] args) {
Timer T = new Timer();
T.Elapsed += Run;
T.Interval = 100;
T.Start();
}
static void Run(object source, ElapsedEventArgs e) {
}

Related

Possible causes for thread/timer delay?

In relation to a previous question of mine ([question] : Which thread will timer method run in? ), I've added a Timer to my Windows Forms app to run every 100ms to show how long the program session has been running. I've defined it as follows (these are only the snippets relevant to the timer):
private System.Timers.Timer timerPureTime = new System.Timers.Timer(100);
timerPureTime.Elapsed += new System.Timers.ElapsedEventHandler(updateTimeElapsed);
this.timerPureTime.SynchronizingObject = currentForm; //where currentForm is my main Form
public void updateTimeElapsed(object sender, ElapsedEventArgs e)
{
if (currentForm.lblTimeElapsed.InvokeRequired) //lblTimeElapsed is your standard Windows Form label
{
currentForm.lblTimeElapsed.Invoke((MethodInvoker)delegate //also, trying to make make GUI invoking thread-safe here
{
TimeSpan t = TimeSpan.FromSeconds(purelyTime);
string showTime = string.Format("{0:D2} min {1:D2} sec",
t.Minutes,
t.Seconds);
currentForm.lblTimeElapsed.Text = showTime;
});
}
else
{
TimeSpan t = TimeSpan.FromSeconds(purelyTime);
string showTime = string.Format("{0:D2} min {1:D2} sec",
t.Minutes,
t.Seconds);
currentForm.lblTimeElapsed.Text = showTime;
}
purelyTime += 0.1;
}
As I understand it the Timer should be running in a thread of its own (taken from the Threadpool) however it still experiences some delay every now and then, throwing the timer off-course. Other threads within the application run pretty regularly (every 250ms) and computation-intensive, but shouldn't these be independent of Timer threads?
What could be the possible causes for timer lag in such cases?
Windows cannot guarantee a precisely regular callback for a timer, so you will definitely see that kind of variance.
You need to take a different approach:
Initialise a Stopwatch field in your class.
Call Stopwatch.Restart() when you want to reset the timing.
Inside updateTimeElapsed() use Stopwatch.Elapsed instead of purelyTime.
Note that your code is completely ignoring the amount of time spent in the timer handler function itself. Inside the handler, you are using Invoke to send a message to the UI and waiting for it to return. That can take an arbitrary amount of time, particularly if the UI is busy.

How to execute code at a specific exact time (far from now) in C#?

I am developping a Windows Service that has to execute a method at a specific exact time.
When the service starts, it extracts several different DateTimes from an SQL Server database and should then start a thread for each DateTime. Each thread should wait until the exact DateTime value, then do some work, then wait again for a shorter period of time and then do some final work again.
I don't want to use System.Timers.Timer because:
the method has to be executed at the exact specified time
this exact time could be in more than 24h
I need to pass a parameter to the Elapsed event
How can I implement this?
Thank you.
EDIT: I just had an idea last night, what if I write a dynamic polling timer? For exemple, if the due datetime is in more than 12 hours it can poll the time every hour to re-synchronize. Then if the due datetime is in more than 3 hours it can poll the time every 30min and so on... What do you think? Would that be a bad code to write?
Thank you again.
You can't pass a parameter to the tick event with System.Timers.Timer, but you can with System.Threading.Timer. The delay time "greater than 24 hours" is no problem. The timers use a 32 bit period that is expressed in milliseconds. 2^31 milliseconds works out to something like 24.85 days. There's also an overload that lets you specify the delay with a 64-bit signed integer. 2^63 milliseconds is ... several hundred million years.
But having those timers tick at an exact date/time far in the future is problematic because you have to specify the delay time, and a clock change will cause your delay to be too short or too long (think Daylight Saving Time, or user-initiated time changes). You can specify the tick time and have a timer poll the current time every second. It's kind of ugly, but it works.
Another option is to use the Windows Waitable Timer object, which lets you set an exact date and time. Unfortunately, the Framework doesn't include a corresponding object. I wrote an article about it some years ago and published the code. The article is no longer available online, but you can download the code from http://mischel.com/pubs/waitabletimer.zip.
I have used something called ManualResetEvent in the past with a lot of success. Assuming that you know the exact time to run your code then you will be able to calculate estimated time to run (TTR) and subsequent runs should be configured within the first run.
partial class SomeService : ServiceBase
{
private ManualResetEvent stop = new ManualResetEvent(false);
private List<DateTime> times;
private int idxDT = 0;
public SomeService()
{
InitializeComponent();
}
protected override void OnStart(string[] args)
{
this.stop.Reset();
//implement you logic to calculate miliseconds to desired first run time
int miliseconds_to_run = 1;
ThreadPool.RegisterWaitForSingleObject(this.stop,
new WaitOrTimerCallback(ThreadFunc),
null,
miliseconds_to_run,
true);
}
private void ThreadFunc(object _state, bool _timedOut)
{
if (_timedOut)
{
if(this.times == null)
{
//get a list of times to run, store it along with the index of current TTR
this.times = new List<DateTime>();
}
int miliseconds_to_run = (this.times[this.idxDT++] - DateTime.Now).Miliseconds;
ThreadPool.RegisterWaitForSingleObject(this.stop,
new WaitOrTimerCallback(ThreadFunc),
null,
miliseconds_to_run,
true);
}
}
protected override void OnStop()
{
this.stop.Set();
}
}
Of course this highly depends how exact your job start time has to be. ThreadPool class will send a Thread alocation request to the OS, and then it will wait for the next available Thread from the Pool. In some processes with lots of lots of threads this could lead to Thread starvation and your exact times will be late.
You could also try creating Task Scheduler Jobs from .NET but I've never done that before.
Even though you said you don't want to use System.Timers.Timer I'll show you how to do it anyway, as bullet 1 and two in your question don't seem to be valid points against using it in my opinion.
So here's what I do in several applications of mine:
// 1. Create the timer
System.Timers.Timer timer = new System.Timers.Timer();
timer.AutoReset = false;
timer.Elapsed += ...;
// 2. Calculate the number of milliseconds between the scheduled time and the current time
timer.Interval = (scheduledDate - DateTime.Now).TotalMilliSeconds;
// 3. Start the timer
timer.Start();
Done. The event will fire "roughly" at the desired time. Please note that this doesn't work down to the exact millisecond, as Windows is not a real-time OS.
I did face sort-off similar issue and used below solution which might solve your issue.
I used ManualResetEvent class, added a Wait method and made the service wait for the exact time.
protected ManualResetEvent waitEvent = new ManualResetEvent(false);
protected bool Wait(int milliSecs)
{
return !this.waitEvent.WaitOne(milliSecs, true);
}
I used this Wait in OnStart method as below:
protected override void OnStart(string[] args)
{
DateTime nextRun = dt;//datetime from the database
YourProcessOrThreadToRun process = new YourProcessOrThreadToRun();
while (Wait((int)nextRun.Subtract(DateTime.Now).TotalMilliseconds))
{
process.StartProcess();
}
}
YourProcessOrThreadToRun is the thread you want to run on that exact time.

Different behaviour of System.Timers.Timer and System.Threading.Timer

Let me start from saying that it's more a question than a problem that needs to be solved. I have the solution now and things work fine for me. But I wonder why problem occured first time.
This is the code I have right now and it works like I expect:
private void OnNewGameStarted(Game game)
{
_activeGames.Add(game);
TimeSpan delay = game.GetTimeLeft();
var timer = new Timer(delay.TotalMilliseconds) {AutoReset = false};
timer.Elapsed += (sender, args) => GameEndedCallback(game);
timer.Start();
}
private void GameEndedCallback(Game game)
{
if (_statisticsManager.RegisterGame(game))
_gamesRepository.Save(game);
_gameStatusSubscriber.GameStatusChanged(game);
}
I used to use System.Threading.Timer instead of System.Timers.Timer and sometimes timer event (GameEndedCallback method) fired and sometimes not. I couldn't find any reason why it was that way.
This is the code I used to initilize timer (other parts are the same):
TimeSpan delay = game.GetTimeLeft();
new Timer(GameEndedCallback,game,(int)delay.TotalMilliseconds,Timeout.Infinite);
}
private void GameEndedCallback(object state)
{
var game = (Game) state;
Method OnNewGameStarted is event handler and it is called after chain of methods from Fleck webserver when some certain message comes to it.
There is a post about the 3 timer types and what they do.
the main things are:
System.Timers.Timer is for multithreading work
System.Windows.Forms.Timer - from the application UI thread
System.Threading.Timer - not always thread safe!
Timeout.Infinite is The time interval between invocations of callback, in milliseconds. Specify Timeout.Infinite to disable periodic signaling. See MSDN: http://msdn.microsoft.com/en-us/library/2x96zfy7.aspx
Timeout.Infinite is a constant used to specify an infinite waiting period.
Try this to get perodic calls to the callback
new System.Threading.Timer(GameEndedCallback, game, (int)delay.TotalMilliseconds, (int)delay.TotalMilliseconds);

How to use signalling mechanism for performing intensive work (that do not overlap) with a thread and manualresetevent in C#?

I have an existing application with 1 thread running some intensive work in the background every numOfMinutesInterval. This was previously done using Thread.Sleep (sleeping for the entire interval period) but I've read that Thread.Sleep is evil and it's sloppy design, so I wanna change to a signalling mechanism. Below is the code I just wrote (using dispatcher timer from wpf, but I think in this small scenario it's the same for winforms timer as well).
The dispatcher (running in the UI thread) ticks every second, and inside the tick function it checks whether interval has passed, and if so, it will signal the manualresetevent Set(). I'm wondering if this is bad design if the intensive work extends pass the interval period? If I set the numOfMinutesInterval = 1, but the work took 1 minute and 1 second, does that mean we'll skip 1 set() call, since the tick is attempting to set() the event while work is still being done and the worker thread is not yet blocking.
Please notice also that I've set lastWorkDoneTime = DateTime.Now; after calling Set(), should I move it to the worker thread instead (calling lastWorkDoneTime = DateTime.Now; just before manualResetEvent.WaitOne();)?
If this is bad design, what should I do to change it? Thanks for reading!
//thread work done here
private void MyDoWork_ThreadStart()
{
while(FlagApplicationStillRunning == true)
{
//do the intensive work here
manualResetEvent.WaitOne();
}
}
// tick every second
private int numOfMinutesInterval = 1;
private DateTime lastWorkDoneTime = DateTime.Now;
private void DispatcherTimer_Tick(object sender, EventArgs e)
{
if((DateTime.Now - lastWorkDoneTime).Minutes > numOfMinutesInterval)
{
manualResetEvent.Set();
lastWorkDoneTime = DateTime.Now;
}
}
You could just start a task and have that perform the intensive work.
private void DispatcherTimer_Tick(object sender, EventArgs e)
{
if ((DateTime.Now - lastWorkDoneTime).Minutes > numOfMinutesInterval)
{
Task.Factory.StartNew(DoIntensiveWork());
lastWorkDoneTime = DateTime.Now;
}
}
As far as setting the lastWorkDoneTime that is up to you. If you set it in what fires off the task, you have the possibility of two or more tasks running at the same time performing the work. If you set it at the end of the function performing the work you introduce a delay that is based on how long it takes to complete the work.
I would actually look into using one of the timer objects and let that handle the timing for you instead of using the DispatcherTimer_Tick event. There is System.Timers.Timer, System.Threading.Timers, and others.
To help determine what timer option would work best for you:
Comparing the Timer Classes in the .NET Framework Class Library

C# timers.timer is not working properly

I'm trying to use a timer in C# to run a method at an interval of five seconds. Though this code doesn't seem to work. I do not get any errrors when running it but the program (I run this in a console) shuts down right after IP.timer1.Start(). The timer1_Elapsed method is never getting executed. I know that because I've tried making the program print a string to the console at the first line of the timer1_Elapsed method.
class Program
{
Timer timer1 = new Timer();
static void Main(string[] args)
{
Program IP = new Program();
IP.timer1.Elapsed += new ElapsedEventHandler(timer1_Elapsed);
IP.timer1.Interval = 5000;
IP.timer1.Enabled = true;
IP.timer1.Start();
}
static void timer1_Elapsed(object sender, ElapsedEventArgs e)
{
//Function to get executed each time the counter elapses.
}
}
The reason is that the Start method of the timer starts the timer on another thread, and immediately returns from the method. This causes your Main method to end, and the console to shut down.
Depending on what Timer you are using (there are a few similarly named classes in the BCL) you may want to implement the fix differently. I suggest reading the documentation on System.Timers.Timer, System.Windows.Forms.Timer or System.Threading.Timer depending on which it is you are using.
Your program will exit the moment the main function terminates.
You need to prevent main from exiting until you are ready, possibly with a Console.ReadLine();
The timer starts on another thread, Use the following to suspend the thread until the user hits a key after the timer start.
Console.ReadLine();
The reason that the program exits right after IP.timer1.Start() is that it is done executing the Main()-function and there is nothing stopping it from returning.
If you want a simple way to keep your program running you can add Console.ReadKey(); after timer1.Start(); so that your application will wait until that function returns (which is when you press any key). After doing this your callback should be called every five seconds as specified.

Categories

Resources