Callback with a time - c#

I want to implement a method that callback a method at a precise time. We can have more than a method that can be called at the same time.
public void CallmeBack(DateTime time, Action callback)
{
}
What's the best implementation in C# ?
My quick and dirty solution was to create a dictionary Dictionary<DateTime, List<Action>> and to make a timer every each (minute/second) and check the time (DateTime.Now) and a current time in the test mode.
The solution have to be "Safe" if the current machine time changed. So a simple solution like this couldn't work :
Timer timer = new Timer((param) => {callback.Invoke();}, null,
(long)(time - DateTime.Now).TotalMilliseconds, Timeout.Infinite);
Edit :
Typical case where simple timer don't work is DST and manual time/date adjustment.
Plus, I just want the callback executed once not multiple times.

What you are looking for is a cron library. There are many out there. Some have a lot of features and are a bit heavy. Here is a blog post about cron jobs and a library that I have used in production code.
http://blog.bobcravens.com/2009/10/an-event-based-cron-scheduled-job-in-c/
Hope that helps get you started.
Bob

A couple of alternatives you may want to consider:
You could use a task scheduler such as :http://taskscheduler.codeplex.com/
You could stick with a timer and listen for time changes using: SystemEvents.TimeChanged. That event is triggered by user time changes. I assume you can handle predictable time changes (daylight saving etc.) when setting the timer in the first place. I'm not sure about NTP-related changes - you'd need to investigate that further.

Related

Why Timer has no properties, how to get it's interval after initialization?

I'm using a System.Threading.Timer in my windows service for nightly import routines. It looks every minute into the database for new files to be imported. Now, since the service runs all day long, i want to change it so that it runs at night every minute and at day every 5th minute.
Therefore i thought i could check the current time, between 7am and 10PM use the day-interval-configuration value, otherwise the night-interval.
Now to the actual question: why is there no property in the Timer-class which indicates the current period/interval? Then i could decide whether i have to change it or not according to it's value.
As a workaround i could store it in an additonal field, but i wonder if it's possible to get the value from the timer itself.
Note that i'm using this constructor:
//start immediately, interval is in TimeSpan, default is every minute
importTimer = new System.Threading.Timer(
ImportTimer_Elapsed,
null,
TimeSpan.Zero,
Settings.Default.ServiceInterval_Night
);
Why is there no property in the Timer-class which indicates the current period/interval?
I assume (I'm not part of the .NET implementation team, so have to assume) this is because it used a Win32 Waitable Timer. And there is no API to get the settings of a Waitable Timer.
Note, if such properties did exit there would be a race condition:
Thread 1 reads the property and starts some business logic based on it
Thread 2 changes the property (invalidating thread 1's logic)
Thread 1 updates the property.
while any specific use of a timer may not suffer this, the general case has to cater for it.
(In Win32 this is even worse a WaitableTimer can be named, and thus accessed from other processes.)
You can use System.Timers.Timer instead, which provides such a property (".Intervall")
System.Threading.Timer does not have an internal field with the intervall value. I took a look into the .net code and i saw it isnt possible to get the current period by reflection.
Don't mess around with the tick rate. Instead invoke your code after a fixed number of ticks, depending on time:
private void ImportTimer_Elapsed(object o)
{
tickCount--;
if (tickCount <= 0)
{
// do your stuff
tickCount = Between7AMAnd10PM() ? 5 : 1;
}
}

Check mouse pointer state using callback

I need a reliable method to check the mouse pointer state, and to count how many times it has changed, e.g. from 'normal' pointer to the hourglass/circle or vice versa. It is part of a performance test that measures response times, and the only way to determine whether a certain business process has finished is by observing the mouse pointer, and to count how many times it has gone from "normal" to "busy" and back again. Once it done this twice, the process is finished. I know - it's horrible, and a rubbish workaround, but it's the only thing I can use.
I have implemented something that works, but it has one crucial weakness: if the mouse pointer changes while the thread has gone to sleep, then I "miss" this change and consequently the exit condition. I will reduce the wait time to 5 or 10 milliseconds, but it's still not a good solution.
Here's the code I have, to give you an idea of what's going on:
TimeSpan timePassed = new TimeSpan();
bool lastMousePointerState = ConvertMousePointerStateToBoolean(Mouse.CursorName);
bool currentMousePointerState = true;
Stopwatch stopWatch = new Stopwatch();
stopWatch.Start();
while(pointerChanges <= 1 && timePassed.Seconds < synchDurationTimeout)
{
Thread.Sleep(100);
currentMousePointerState = ConvertMousePointerStateToBoolean(Mouse.CursorName);
var variableComparison = lastMousePointerState ^ currentMousePointerState;
if (variableComparison.Equals(true))
{
pointerChanges++;
}
timePassed = stopWatch.Elapsed;
lastMousePointerState = currentMousePointerState;
}
I had a look at this article to see if perhaps I could make use of callback functions, and what the article describes does work but only for mouse actions, not its state. Since I have practically no experience with callbacks and making calls out to the OS from .NET, I was hoping someone could tell me if a) what I have in mind is generally possible, and if so b) perhaps provide a working code snippet that would achieve what I need.
Thanks in advance !
Edit: I think the GetCursorInfo function might be what I need, but the description is so terse as to be useless to me ;-)
Despite the overwhelming number of responses here, I'd like to answer my own question :-)
What I ended up implementing (and what is good enough for my purposes) is to use the code that was provided by Atomic Object.
I simply generate the dll from the C++ code, and use a loop to check the state. It is still not as good as a callback/notification mechanism, but I need to finish this and this is the best solution to date.

how to run code depending on the time

I have a little problem. I didn't find a suitable title, sorry
I have a time column at my database and I want to do something (not important) whenever currenttime==timeValueAtMyDatabase. How?
if(currenttime==timeValueAtMyDatabase)
{
//do something
}
If you are okay with the code executing in a different thread and you can use whatever libraries you want (Rx in this case), I personally prefer this method:
Observable.Timer(timeToDoTheThing).Subscribe(codeToRun);
timeToDoTheThing is the time that the code should be executed at and codeToRun is the code that will run when the time is reached (in the form of a void returning delegate that takes one long parameter).
Some things to note:
The event will occur immediately if the time provided is in the past.
The event will execute in a background thread. You can control which thread it runs in by providing a scheduler, but that is a bit more complex and I prefer to just make my code thread safe rather than trying to control which threads execute which blocks of code.
Below is a complete program that will exemplify this. You will need to install the Rx-Main NuGet package to the project for it to work and build against .NET 4+.
using System;
using System.Reactive.Linq;
using System.Threading;
namespace Test
{
public class Class
{
public static void Main()
{
var timeToDoTheThing = new DateTimeOffset(2013, 10, 19, 22, 19, 30, TimeSpan.Zero);
Action<long> codeToRun = _ => Console.WriteLine("It is time.");
Observable.Timer(timeToDoTheThing).Subscribe(codeToRun);
Thread.Sleep(100000);
}
}
}
If this is a Windows Forms Application, you can use a timer and check whether some of the entries are less then DateTime.Now.
If it is a web application, you can use a cron job. Check out the following link: Creating Cron Jobs in C#.
Use a timer control that ticks on appropriate intervals.
On ever tick compare the current time with the time in your database.
You will need to account for differences. For example if it ticks at 0.1sec, 1.1sec, 2.1sec and the time in your database is 1sec.
You'll have to find an appropriate way to account for such differences.

Disable capture keys when program is unresponsive

I have a winform application that can get pretty unresponsive during heavy calculations. For example, when user presses F10 key, the program will starts some heavy stuff and remains unrsponsive for a while (I know this is not a desired way of program flow but I don't want to alter the way program works at the moment).
Now the problem is, during this time if user presses F10 again, the program will start doing the same thing as soon as it has done the first process.
How to disable capturing keys at a certain point and enable it again?
The program is not "capturing the key", it is queued by the operating system because your main UI-Thread is busy with your calculations and doesn't handle anything at that time. The only thing i could think of what you could do is to check that a certain time has elapsed after the last run has finished before you allow another run. An ugly hack in my humble opinion.
But, yeah, thats why you should use backgroundworkers or threading. Using a BackgroundWorker is a lot easier than it may seem at the beginning.
Ideally you should use a BackgroundWorker here but as you said
I don't want to alter the way program works at the moment).
So I won't go into that path.
What you can do is when you detect F-10 for the first time set a bool value to true and next time whenever you detect f-10, check if the bool is already true or not. If it is already true don't start the heavy operation again simply skip the code.
At the end of heavy processing set the bool to false again.
I would agree with Jason on the whole - hacks and temporary fixes have a nasty habit of becoming 'features' of a program.
However, to answer your question, I would suggest having a disable flag in your program that disables the desired functionality whilst your calculations are running. You could then put in the event handler a check for the flag :
public bool DisableFlag { get; set; }
public void MyKeyEventHandler(object sender, EventArgs e)
{
if (DisableFlag)
{
return;
}
// Do stuff
}
Hope that helps!
Cheers,
Chris.
EDIT :
Thinking about Ken's comment, and this is true, the event will be queued and it will only be useful as long as some events are bleeding through. So, the other option is to disable the even handler altogether by doing
myControl =- MyKeyEventHandler;
and then
myControl =+ MyKeyEventHandler;
when the calculations are finished. This way, no events are queued and you avoid the problem as described by Ken!!

C# - Alternative to System.Timers.Timer, to call a function at a specific time

I want to call a specific function on my C# application at a specific time. At first I thought about using a Timer (System.Time.Timer), but that soon became impossible to use. Why?
Simple. The Timer class requires a Interval in milliseconds, but considering that I might want the function to be executed, let's says in a week that would mean:
7 days = 168 hours;
168 hours = 10,080 minutes;
10,080 minutes = 604,800 seconds;
604,800 seconds = 604,800,000 milliseconds;
So the interval would be 604,800,000;
Now let's remember that the Interval accepted data type is int, and as we know int range goes from -2,147,483,648 to 2,147,483,647.
That makes Timer useless, not in this case, but in the case of more than about 25 days, once we cannot set a Interval bigger that 2,147,483,647 milliseconds.
So I need a solution where I could specify when the function should be called. Something like this:
solution.ExecuteAt = "30-04-2010 15:10:00";
solution.Function = "functionName";
solution.Start();
So when the System Time would reach "30-04-2010 15:10:00" the function would be executed in the application.
How can this problem be solved?
Additional information: What will these functions do?
Getting climate information and based on that information:
Starting / Shutting down other applications (most of them console based);
Sending custom commands to those console applications;
Power down, rebooting, sleep, hibernate the computer;
And if possible schedule the BIOS to power up the computer;
EDIT:
It would seem that the Interval accepted data type is double, however if you set a value bigger that an int to the Interval, and call Start() it throws a exception [0, Int32.MaxValue].
EDIT 2:
Jørn Schou-Rode suggested using Ncron to handle the scheduling tasks, and at first look this seems a good solution, but I would like to hear about some who has worked with it.
Your "Start()" method should spawn a thread that wakes up at a defined interval, checks the time, and if you haven't reached the desired time, goes back to sleep.
I would recommend that you just write a program that deals with the business part of it and then execute that program when necessary by using Windows Task Scheduler.
One approach to task scheduling, simliar to that proposed by klausbyskov, is to built your scheduling service on top of an existing .NET scheduling framework/library. Compared to using the Windows Task Scheduler, this has the advantages of (a) allowing several jobs to be defined in the same project and (b) keeping jobs and scheduling logic "together" - i.e. not relying on server settings prone to get lost in system upgrades/replacements.
I know of two open-source projects that offer this kind of functionality:
"Quartz.NET is a full-featured, open source job scheduling system that can be used from smallest apps to large scale enterprise systems." I have never actually used this framework myself, but from studying the website, I have the impression of a very solid tool, providing many cool features. The fact that there [quartz-net] tag on Stackoverflow might also indicate that it is actually used in the wild.
"NCron is a light-weight library for building and deploying scheduled background jobs on the .NET server platform." It does not have half as many features as Quartz.NET, and it does not have any tag on Stackoverflow, but the author (yours truly) believes that its low-friction API makes it somewhat easier to get started with.
Building your scheduling service on top of NCron, you can schedule a CleanupJob for weekly execution using a single line of code:
service.Weekly().Run<CleanupJob>();
Ok, you will need around three lines of boiler plate code on top of that to actually turn your project into a Windows service, but it sounds more impressive when I claim that it can be done with one line of code ;)
You could write some sort of wrapper class for a Timer which takes a DateTime instance. Then you perform the following steps:
Determine the difference between DateTime.Now and the desired time.
If the difference (in milliseconds) is larger than the maximum allowed value for the Timer.Interval property, set the Interval to the maximum allowed value (i.e. double.MaxValue or whatever) and start it.
Now, when the timer elapses the first time, you simply go back to step 1.
At some time, the difference will be smaller than the maximum allowed value for the Interval property, and then you could fire an event in your wrapper which ultimately calls the desired method.
Use the System.Threading.Timer:
var timer = new System.Threading.Timer(delegate { }, // Pass here a delegate to the method
null,
TimeSpan.FromDays(7), // Execute Method after 7 days.
TimeSpan.Zero);
You can use the System.Threading.Timer class, which provides a constructor accepting an interval expressed as an Int64, which should be enough for your needs.
Now for the other stuff :
You can start/stop/configure program using the Process class (I don't really get what you call "custom commands")
You cannot restart or shut down or control the local BIOS using native .NET classes. Rebooting / restarting is possible through Interop (calling native Windows API from .NET), and scheduling the BIOS is just impossible. Or maybe with a special server motherboard ? I don't know..
The class System.Threading.Timer has the same limitation too (it would throw an ArgumentOutOfRangeException according to MSDN).
There seems to be no .Net Framework class natively adept to circumvent the Int32.MaxValue milliseconds upper bound.
public static class Scheduler
{
private const long TimerGranularity = 100;
static Scheduler()
{
ScheduleTimer = new Timer(Callback, null, Timeout.Infinite, Timeout.Infinite);
Tasks = new SortedQueue<Task>();
}
private static void Callback(object state)
{
var first = Tasks.Peek();
if(first.ExecuteAt<DateTime.Now)
{
Tasks.Dequeue();
var executionThread = new Thread(() => first.Function());
executionThread.Start();
}
}
private static Timer ScheduleTimer { get; set; }
public static void Start()
{
ScheduleTimer.Change(0, TimerGranularity);
}
public static void Add(Task task)
{
Tasks.Enqueue(task);
}
public static SortedQueue<Task> Tasks { get; set; }
}
public class Task : IComparable<Task>
{
public Func<Boolean> Function { get; set; }
public DateTime ExecuteAt { get; set; }
public int CompareTo(Task other)
{
return ExecuteAt.CompareTo(other.ExecuteAt);
}
}
The solution I'd use is something similar to the above example: a class Scheduler that manages all the Tasks (in order to avoid having a timer for each task we are going to schedule).
Tasks are added to the a queue able to perform sorted insertion. Note that SortedQueue<T> is not a type of the .Net Framework but an hypothetical, easy-to-code collection capable of sorted insertion on a comparable type T.
The scheduler awakes every TimerGranularity milliseconds and checks for the first task whose `ExecuteAt' time has been surpassed; then executes it on a separate thread.
Additional effort could be done by creating a list of all surpassed tasks (instead of the first one only); but I left it out for the sake of clarity.
There is exist exist nu-get called Quartz.NET.
You can use it exactly for this.

Categories