I have an application in which the user is able to create different notifications, like sticky notes and set their starting times. When he presses the start button a timer starts and these reminders should pop up at the time they were set for. I've searched for other answers, like this one, but the problem here is the notifications' times are different.
So what is the best way to schedule the events that activate the notifications?
I can think of two possible ways with their Pros and Cons:
Run a DispatcherTimer, that ticks every second and checks whether the time for a notification has come and pop it up. Pros: single DispatcherTimer instance. Cons: ticking every second and checking all notifications is an overhead.
Create a DispatcherTimer for each notification and let them handle time themselves. Pros: every timer ticks just once to pop the notification. Cons: too many timers is an overhead and may be hard to control.
Am I on the right track? Which of the two approaches is better, resource wise? Is there a third better way I am overlooking?
EDIT: If it makes any difference, the notifications should also auto close after some user-defined time and repeat at regular user-defined intervals.
I've used many methods to schedule events in C# Applications (Threads, Timers, Quartz API...), and I think that the Quertz.NET API -link- is the best tool you'll find (For me at least). It's easy and simple to use.
Example of your job class:
public class HelloJob : IJob
{
public void Execute(IJobExecutionContext context)
{
Console.WriteLine("Greetings from HelloJob!");
}
}
Example from the internet:
// Instantiate the Quartz.NET scheduler
var schedulerFactory = new StdSchedulerFactory();
var scheduler = schedulerFactory.GetScheduler();
// Instantiate the JobDetail object passing in the type of your
// class. Your class needs to implement a IJob interface
var job = new JobDetail("job1", "group1", typeof(HelloJob));
// Instantiate a trigger using the basic cron syntax.
// Example : run at 1AM every Monday - Friday.
var trigger = new CronTrigger(
"trigger1", "group1", "job1", "group1", "0 0 1 ? * MON-FRI");
// Add the job to the scheduler
scheduler.AddJob(job, true);
scheduler.ScheduleJob(trigger);
You'll find a helpful code example in the QuickSart guide here.
Regards.
If the notification system is going to be used inside single process, continue with single dispatcher timer. Make sure the dispatcher timer is set to the near notification. and each time a new notification is created or timer hit ,change the time to next nearest notification.
That way you can avoid processing every time.
eg: First time when somebody creates notification point timer to that time. If someone else create another notification before first hits change the timer to second. If the second time is after the first time, change the timer after dispatching the first notification call back. If its threaded you may need to work hard to get thread safety.
If notification is needed across process use windows task scheduler which already knows how to run timer and call our code on time. You may need to use some sort of IPC (WCF net.pipe, msmq etc...) to achieve notification.
Related
I am writing a "game" simulating Student's Adventures at The University and what I have done already is few forms, still I need one form to not wait for user input but check if I want an Game Event to run now, if not, then wait few seconds and then skip to another day and repeat the procedure for that day.
The thing is user is able to quit the game at any time and all the information is saved so I need to keep it an one-shot timer of few seconds that doesn't run for another time after it expires.
How do I write an one-shot timer or delay an execution of my c# code for few seconds?
EDIT:
MessageBox.Show("I will wait 3 seconds now");
wait 3 seconds
...
after 3 seconds
MessageBox.Show("3 seconds passed since I poped out last message box!");
If all that you want to do is create a method to "tick" every so often, there are a few options.
The first would be the System.Threading.Timer object, documented on MSDN here: http://msdn.microsoft.com/en-us/library/system.threading.timer%28v=vs.110%29.aspx
An example of this:
public void Tick(object stateInfo /* required to fit TimerCallback signature */)
{
/// add your code here
}
And your Timer instantiation would look like so:
System.Threading.Timer timer = new System.Threading.Timer(Tick, null, 0, 3000);
And thereafter Tick() will be executed every 3 seconds. Feel free to replace the null with an object of your choice so as to keep track of state.
A second, worse choice would be to use a BackgroundWorker. The primary advantage I've found in this is that the ProgressChanged event handler is automatically invoked in the primary UI thread, so you can use it fairly easily for cross-thread code that involves the UI in some sense. Here's the documentation on MSDN: http://msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker%28v=vs.110%29.aspx
I don't think the BackgroundWorker would be a good choice - it's user-friendly, but it's not really designed to persist infinitely, or activate periodically, so its usage leads to bad workarounds like wrapping all the DoWork code in a while(true) loop and using Thread.Sleep() to pause execution.
A third would be the System.Timers.Timer object, which takes an Interval in milliseconds and an Elapsed event hooked into one of your methods. Each time the interval passes, your method is called. The documentation for that is here: http://msdn.microsoft.com/en-us/library/system.timers.timer%28v=vs.110%29.aspx
Note that all of these work slightly differently, so one may well fit your use case significantly better. We can't really tell you which one is best because we don't really know much about your implementation right now.
http://msdn.microsoft.com/library/system.threading.timer.aspx
static void Main(string[] args)
{
Timer tmr = new Timer(S, null, 0, 5000);
Console.Read();
}
static void S(object obj)
{
Console.WriteLine("1");
}
and u can look here
Execute a method after delay on time only
Quart.Net by default only uses the priority of a job if it is triggered at the same time as another job. If two jobs are triggered at different times however, the earliest one will always be run first on the thread pool. I have a scenario though where I need the highest priority job in the queue to always run on the next thread. Is there an easy way to do this with Quartz.Net, or will I have to implement my own scheduler if I wanted this done? (Or move to another technology).
The specific scenario I have in mind:
Periodically jobs will be triggered at a high priority that may produce some output for another process. Minimizing wait times here is reasonably important. However, I also have times where I may trigger batches of up to several thousand jobs at once at a much lower priority. I'm worried that when these "batches" are triggered, that the much more important work will wait too long to run.
Is there an easy way to do this with Quartz.Net or a rival technology?
Have you seen Trigger Priorities? I don't think it will run it on a different thread, but it will push the job to start before another job that was triggered before with lower priority.
Trigger trigger = TriggerBuilder.Create()
.WithIdentity("TestTrigger")
.StartNow()
.WithPriority(10)
.Build();
As you mention, this isn't directly supported by Quartz.Net. You could create your own scheduler (see below) or you can work around it if you're using a database store by updating the NEXT_FIRE_TIME column in the QRTZ_TRIGGERS table. If you update the NEXT_FIRE_TIMEs so that they are ordered by the priority, then the next time the scheduler checks for a schedule change, your jobs will be executed in priority order.
There is a
public void SignalSchedulingChange(DateTimeOffset? candidateNewNextFireTimeUtc)
method on the QuartzScheduler that you could call after updating the fire times but unfortunately it's not exposed by StdScheduler. If you're going down the "my own scheduler" route, you would call this directly. Otherwise, calling the ScheduleJob method on the scheduler (and scheduling a job) calls this as well, so you could leverage that and schedule a job after updating your next fire times.
The easiest way to implement this behavior is to subclass StdAdoDelegate (or one of the DB specific implementations) and override GetSelectNextTriggerToAcquireSql so that it sorts by PRIORITY before NEXT_FIRE_TIME instead.
The following class fetches the default SQL query and swaps the order by clauses with the help of a temporary null character placeholder:
public class CustomAdoDelegate : StdAdoDelegate
{
protected override string GetSelectNextTriggerToAcquireSql(int maxCount)
{
return base.GetSelectNextTriggerToAcquireSql(maxCount)
.Replace(ColumnNextFireTime + " ASC", "\0")
.Replace(ColumnPriority + " DESC", ColumnNextFireTime + " ASC")
.Replace("\0", ColumnPriority + " DESC");
}
}
Keep in mind that this could result in long delays for lower priority jobs if the scheduler is overwhelmed with higher priority ones.
I haven't tried it myself but it might be worth considering some kind of hybrid approach that balances the PRIORITY and NEXT_FIRE_TIME values somehow. For example, you could subtract the priority in seconds from the next fire time to create a kind of variable sized priority window.
order by dateadd(ss, -PRIORITY, NEXT_FIRE_TIME)
So a priority=10 trigger would only beat a priority=5 trigger if it was triggered no more than 5 seconds later. Just a thought.
This is a rather simple issue, but every time I try to find the answer it keeps showing things about Windows Scheduled Tasks, and this is not what this is.
Say my program is basically this:
void StartDoingThings()
{
//At Specific System.DateTime
DoSomething()
//At another specific System.Datetime
DoSomethingElse()
}
What do I put instead of those comments to cause those methods to run at separate datetimes.
I could use Thread.Sleep() or even System.Threading.Timers and calculate intervals based off of (DateTimeOfEvent - DateTime.Now), but is there simply something to say (assuming the program is still running): At 9:30:00 AM on 11/30/2012, perform the method DoAnotherThing() ?
If you want to "schedule" a method to do something at a predetermined time, there are a number of ways to do that. I would not use Thread.Sleep() because that would tie up a thread doing nothing, which is a waste of resources.
A common practice is to use a polling method that wakes up on a regularly timed schedule (let's say once a minute) and review a shared list of tasks to perform. System.Timer can be used for the polling method:
aTimer = new System.Timers.Timer(10000);
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
The OnTimedEvent method can contain code that maintains a collection of "tasks" to perform. When a task's time comes up, the next run of the Timer will cause it to execute.
I am working on a project where I need to let the user create one (or more) timers to fire off an event.
The user is supposed to define variables such as if the timer should be active and how often the timer will fire along with some other variables of what will happen when the timer is fiering.
All these variables are stored in a dictionary (Disctionary) where the object holds all the variables the user has set and the string is the name that the user has chosen for this timer.
I then want my program to loop through this dictionary and search for all objects which has the variable t_Active set to true (this I have already achieved).
What I need help with figuring out is the follwoing:
When it detects the variable, and if it's set to true, I need the program to see if there is already a timer created for this.
If it isn't, it should create one and set the relevant parameters for the timer.
The two variables t_num and t_period should decide the interval of the timer.
t_num is an int and t_period is a string which will be set to either minutes, hours or days.
Combining t_num with 60000 (minutes), 3600000 (hours) or 86400000 should give the corrct interval.
But how would I go on about programatically create a timer for each user-defined active object?
And how do I get the program to detect wether or not a timer has already been created?
I have been searching both here and on google, but so far I haven't come across something that makes sense to me.
I am still learning C#, so what make sense to you guys may not neccessarilly make sense to me yet. :)
I hope I have explaned what I need good enough, please do ask me to clarify if you don't get me.
Edit:
Maybe I should also mention that the mentioned dictionary will also be saved to an XML file to that the user can pick up all the settings they made at any time.
Edit 2:
#hatchet I am wondering wether or not this will work.
I have tried to make it work, but are bumping in to some difficultied (because I lack the experience and don't fully understand your pseudo-code. I am getting errors, a few that I could sovle, and a few that I couldn't. (I didn't expect fully working code, don't worry)).
Also, the user should be able to modify the timer.
In the mainform, there's a few textboxes and three buttons.
The form is used to send messages.
The user can choose to manually send their message, to add the message to a timer, or to edit the timer.
When the user hits the manual button, the messages goes out to all receivers once.
If the add the message to a timer, a new subform pops up, where they are able to set the following details:
string Name (of timer)
DateTime Start_date
CheckBox Ending
DateTime End_date
NumericUpDown Seconds (minimum value of 15 minutes)
Combobox Minutes, Hours, Days
Checkbox Active
When the user adds the message to a timer, the TimerSettings gets in to the dictionary as sting,Object (my custom object cointaing all the details).
If they hit the modify button on the main form, it is thought that before the subform is opened, the program looks for the correcponding timer (the mainform has a combobox with all added timers), stops the timer and then opens the subform to let the user edit the details.
On the subform is also a delete button so that the user can delete the timer.
When adding or modifying the timer, mainform is catching it and writes the changes to the XML file and the combobox.
And here is where it should look if there's already a timer for this message and create on of there isn't, or restart the timer if there are.
I am not sure how I should make your solution work for this though.
THe procedure of sending the messages takes anything from 30 seconds to 5 minutes depending on the number of receivers (can't be more than 42 (the program is an interface to another program which doesn't allow for more than 42 receivers)).
I understand that several timers could be an issue, but I doubt that any user would need more than max 10 timers anyway, so there could be a built in limitation of, lets say, 15 timers.
This is kind of pseudo code C#, to convey the idea. I have done this same thing, but there are enough little details that are different, that pasting that code would be confusing. So off the top of my head, this semi-code will hopefully be close enough to real code to show you what I meant by my comment to your question.
Say you have a class like this
public delegate void Work();
public class TimedThing {
public int IntervalSecs;
public DateTime NextFiring;
public event Work OnWork;
}
Then you have a controller class
public class TimedGroup {
TimedThing[] things;
System.Timers.Timer timer;
public TimedGroup() {
this.timer = new System.Timers.Timer();
this.timer.AutoReset = false;
this.timer.Elapsed += TimerFired;
}
...
// some methods for adding and removing TimerThings
...
public void Start() {
this.timer.Interval = 1; // just to get things started
this.timer.Enabled = true;
}
public void Stop() {
this.timer.Enabled = false;
}
private void TimerFired(object sender, System.Timers.ElapsedEventArgs e) {
DateTime now = DateTime.Now;
// let's have timer fire at least as frequently as every 5 minutes
// if we need to have it fire sooner than that, it will get set below
DateTime next = now.AddMinutes(5);
foreach(var thing in this.things) {
if (thing.nextFiring <= now) {
var task = Task.Factory.StartNew(() => DoWork(thing));
thing.NextFiring = thing.NextFiring.AddSeconds(thing.IntervalSeconds);
// or maybe this is more appropriate
// thing.NextFiring = Now.AddSeconds(thing.IntervalSecs);
}
if (thing.NextFiring < next) next = thing.NextFiring;
}
// set the timer to fire whenever the next soonest work needs to be done
this.Timer.Interval = (next - now).TotalMilliseconds;
this.Timer.Enabled = true;
}
private void DoWork(TimedThing thing) {
thing.Work();
}
}
There are likely details though that have to be dealt with, although many of these details have to be dealt with whether you are using a timer for every thing, or a single timer for them all. For instance, what if the work for a thing normally takes 10 seconds, but occasionally it may take 60 seconds, and they have a time interval set for 45 seconds. Sometimes the next firing will want to run that work again, although the previous work started on the previous firing is still running. That may or may not be desirable, depending on what kind of work these things are doing. If it isn't desirable, you have to add some monitoring of the tasks that get spawned so you will know if you need to skip doing the work because the previous work isn't done yet. Another thing is coding a graceful winding down. When you set the timer.Enabled to false (or timer.Stop()...which is the same thing), there is a brief period of time where the timer event can still fire, even though you stopped the timer (see Why does System.Timer.Timer still fire events when Enabled is set to false?). That can make for some weird behavior/bugs.
I'm not sure how well timers will scale with that approach. It might be worth investigating other approaches to managing these events. As #hatchet just made a comment, you could have 1 timer for the next event.. with that approach, you can set up the next one when it runs.
Another possibility is using a database and a timer that runs every <small time period> which executes all actions with due time stamps.
I am developing an application in C# 4.0. I need to call a method depending on the current system time. Can I do it using Timer control? It would be great if someone could tell me how to do this.
Thanks,
Rakesh.
You may (and without knowing more about your app I cant say for sure) want to look at it a bit differently. You can easily write an app that sits around, doing nothing except polling what time it is, and then running whatever it is you need to do, but that will leave your application hanging around and doing nothing but taking up resources most of the time.
Instead, maybe you could consider creating a scheduled task, which will let you run your app at any given time. The Task Scheduler is documented at http://msdn.microsoft.com/en-us/library/aa383614(VS.85).aspx, and there is a managed wrapper for it at http://taskscheduler.codeplex.com/. (it says it works on XP or better, so hopefully it will cover your needs).
Good luck,
You can use the below code
System.Timers.Timer _timer1 = new System.Timers.Timer();
_timer1.Elapsed += new ElapsedEventHandler(_timer1_Elapsed);
//1 second
_timer1.Interval = 1000;
_timer1.Start();
//this event will be fired each 1 second
private void _timer1_Elapsed(object sender, ElapsedEventArgs e)
{
}
You should be able to, yes. Ghyath Serhal has told you how to use the timer class in general. The only bit missing is how to do it at a specific time. This should be pretty easy - when you set up the timer just take the time you want the action to happen and the current time, find the difference in seconds and use this to populare the interval. You'll also want to set the AutoReset property to false so that it doesn't start counting down immediately again.
If you ever change the time that the events happen you just need to hook into this with a trigger and update the timer to the new time.
Edit to add: If somebody were to change the system time that may cause problems with this plan. I'm not sure if you can easily tap into that to reset your timers. I'm guessing probably not relevant though. :)
The problem with timer is that it does not guarantee that the elapsed event would be called exactly at the right moment - all you know is that it would be called after time that is bigger than the Interval.
The solution is dependant on the resolution of the time you're interested in - for example if you need to check each minuet if a specific event occurs you can set a timer to raise the event every minuet and then use DateTime.Now to check if the system time is the time the event should occur.
A good policy is to always expect the timer elapsed event to happen several seconds after the Interval set depending on how busy the system is.