Multiple dynamic timers - c#

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.

Related

C# Visual Studio - Wait 3 seconds and do something at the end of method and kill the timer?

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

Waiting for event silence

I need to create a method for listening to events and waiting for a certain amount of silence before calling another function.
Specifically, I am listening to a directory for file updates. When a file change occurs, my "directoryUpdate" function is called. From there I add the file to a list and create a thread called "timerThread" which sleeps for 2 seconds. When that thread is done sleeping, it calls a "gatherFinished" function.
But since directoryUpdate gets called 10 times all at once if 10 files change, it would launch 10 threads which seems like a bad way of doing this.
In the end I want a list of the file changes that occurred within 2 seconds of each other. I figure if there is a way to reset the sleep time to 2 seconds every time a change occurs and wait for the 2 seconds to finish, then I will have what I need. But there is no way to reset the timer as far as I know.
What is the best way of doing this?
UPDATE
Thanks for all your great answers. I am sorry for putting emphasis on getting the list of files. The event (file change) should not matter. I meant to focus on making sure the call to "gatherFinished" happens once at the right time - 2 seconds after all events in question have stopped firing. My question is on the nature of waiting, not on the nature of files or collections.
You could just use an AutoResetEvent and wait 2 seconds on it. If the event is triggered then you loop and wait another 2 seconds.
AutoResetEvent resetTimer = new AutoResetEvent(false);
...
private void TimerJob()
{
...
// The thread will sleep and loop until
// 2 seconds elapse without directory changes
while (resetTimer.WaitOne(2000)) {}
...
}
private void ResetTimer()
{
resetTimer.Set();
}
NOTE: I didn't put any code to specify you how to synchronize the thread that will receive the directory changes and the timer thread. You will have to do that youself.
One way of doing this would be to add each updated file to a list along with a timestamp of when they were added. Then, when your 2-second Timer fires, you can check for any items in the list that have a timestamp older than the last time it fired.
Hey Jono,
This is actually a really fun problem.
If I understand correctly you're using the FileSystemWatcher or some other similar object to monitor a folder.
Each time a file is added or changes, you receive an event.
Now the problem is that this event can be raised at relatively random times, and if you're trying to record all files which have been modified within 2 seconds of eachother, you're going to have many collections of objects.
What I would do is to create a List<List<MyFileChangeClass>> where MyFileChangeClass is whatever construct you use to track the information that changed.
When you handle the event for a file modification, create your new MyFileChangeClass with the necessary details and iterate the outer list. For each list, check to see if the first MyFileChangeClass has a time stamp of less than 2 seconds before the current file modification, if so, add your file modification to the inner list.
Once you're done walking the entire list, add a new List<MyFileChangeClass> to the outer list, which is populated with only the current MyFileChangeClass. This will ensure that future modifications can be associated with the latest one and that you have all groupings of modifications which occurred within 2 seconds of eachother.
Around the entire thing, I'd include a lock - probably a ReaderWriterLockSlim using TryEnterWriteLock().
I hope this helps - if you need more details, please let me know, but obviously you know a bit about what you're doing and probably just needed a bit of logic help because it's a strange problem.
Good luck!
Adam
I am going to assume that you are using the FileSystemWatcher class to monitor for file system changes. Your problem is well suited for the producer-consumer pattern. In your case the producer is the FileSystemWatcher which will add changed files to a queue. The consumer will then dequeue the file names from the queue once they appear. The nice thing about this pattern is that there is only one worker thread involved and all file changes will be processed in the order they are received.
Here is some code to get you started.
public class Example
{
private BlockingCollection<string> m_Queue = new BlockingCollection<string>();
public Example()
{
var thread = new Thread(Consumer);
thread.IsBackground = true;
thread.Start();
}
public void QueueChangedFile(string filePath)
{
m_Queue.Add(filePath);
}
private void Consumer()
{
while (true)
{
// The Take method blocks until an item appears in the queue.
string filePath = m_Queue.Take();
// Do whatever you need to do with the file here.
}
}
}
From the FileSystemWatcher event handlers you would call the QueueChangedFile. Add whatever code you think is necessary to process the file changes in the Consume method after the call to Take. You can make the logic as sophisticated as necessary. If you need to keep track of the time the changes occurred (so that you can later figure out which files were changed within 2 seconds of each other) then instead of having the queue hold a string you could create a simple class that stores both the file path and the change time and have the queue store that wrapper class instead.

C# multiple threads calling single method at specific interval

I will try to make the question as simple so that it is easy to get an idea of the scenario. I am trying to build a stock related application for school project, which is fetching data from the web for a particular stock. So the user inputs stock name in a text box and after clicking the button, the name of the stock is passed to the method downloading data for that particular stock. Now i want that method to be called on every second for the same stock so that user can get the latest updates. Till now no problem. But when the user wants to monitor more than one stocks, i need to dive into threading. As for each stock there will be a thread will be calling the update stock method every second. So for example there are 5 stocks so there should be 5 threads that are working simultaneously calling the method every second to update the results. I hope i have made the problem clear to understand.
To accomplish this i am using the System.Threading.Timer in the button click event and it is calling the method for stock update. But the problem is that when i enter the first stock the method is called only 2 times, for the second stock it is being called for 6 times and for 3rd stock more than 12 times. What is the reason behind such weird behavior.
Any idea if there is any other way around to achieve what i am trying to do.
Following is the code i am working on.
private void button1_Click(object sender, EventArgs e)
{
dataGridView1.Rows.Add("","","","","","test", "test");
int i= dataGridView1.Rows.Count - 1;
string stock = textBox1.Text + ":"+i;
System.Threading.Timer tmr = new System.Threading.Timer(Tick,stock,1000,2000);
}
public void Tick(object stock)
{
lock (locker)
{
string maindata = stock.ToString();
string[] testing = maindata.Split(':');
byte[] data = null;
Uri uri = new Uri("some url where i am getting data from");
WebClient wc = new WebClient();
wc.DownloadDataCompleted += delegate(object sender, DownloadDataCompletedEventArgs e)
{
data = e.Result;
};
wc.DownloadDataAsync(uri);
while (wc.IsBusy)
{
Thread.Sleep(100);
}
string strData = Encoding.ASCII.GetString(data);
string[] s = strData.Split('{');
string data1 = s[4];
string[] data2 = data1.Split('}');
string final = "[{" + data2[0] + "}]";
Form1 obj = new Form1();
List<Form1> jarray = JsonConvert.DeserializeObject<List<Form1>>(final);
dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[0].Value = jarray[0].Symbol;
dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[1].Value = jarray[0].Ask;
dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[2].Value = jarray[0].Volume;
dataGridView1.Rows[System.Convert.ToInt32(testing[1]) - 1].Cells[3].Value = jarray[0].Bid;
}
}
Since with every click you are creating a new Timer. This will mean with every subsequent click, more timers will respond so you start getting the events twice, 4 times, ....
Move this line out of click and put it in the initialization of the form:
System.Threading.Timer tmr = new System.Threading.Timer(Tick,stock,1000,2000);
This does not mean I fully approve your approach since that has nothing to do with the question you are asking.
I suggest you look at Asynchronous Programming Using Delegates. On every tick (using just 1 timer) you should launch a delegate asynchronously to get your values for each stock the user requests.
"But when the user wants to monitor more than one stocks, i need to dive into threading". Not true. Now I don't want to spoil a perfectly good opportunity to dive headfirst into threading, but you don't need to here. Why not refresh all stocks at the same time?
So each time the timer ticks, you download the prices for all the stocks in one go. If you have control of the serverside interface (where you get the data from), make a method that accepts a collection of stocktickers and returns a collection of stockprices. If the server only returns one at a time, you get them on by one in a loop.
Also when you really want to have something that responds quickly, don't poll for new prices every second but have the server notify you when something has changed by subscribing to an event for instance. Some stocks will not move for minutes, while other move very quickly. For most trading purposes, a full second is a lifetime. If you're on WPF, look into DataBinding and INotifyPropertyChanged. That fits extremely well for this type of problem.
GJ
#Prashant - Obviously your approach is not correct. What you actually want to happen is to have multiple threads which will tick at different intervals. As Aliostad hinted at your approach isn't correct.
System.Threading.Timer is a simple,
lightweight timer that uses callback
methods and is served by thread pool
threads. It is not recommended for use
with Windows Forms, because its
callbacks do not occur on the user
interface thread.
System.Windows.Forms.Timer is a better
choice for use with Windows Forms. For
server-based timer functionality, you
might consider using
System.Timers.Timer, which raises
events and has additional features.
What I would do is use a mutex approach to determine if a new thread is required. I would pass the name of the stock and within the thread itself start the timer. If you wanted to a feature to "pause" or "stop" a stock from being watched would be easy enough.
The current class your using is threaded your approach itself is flawed.
As for each stock there will be a thread will be calling the update stock method every second. So for example there are 5 stocks so there should be 5 threads that are working simultaneously calling the method every second to update the results. I hope i have made the problem clear to understand.
Except this isn't what you are doing. What you are actualy doing is starting a new timer thread for each time the button is pressed( for every stock ) which of course is NOT what you actually want to do ( based on your own statements ).

Triggering actions using Timer in C#

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.

How can I have a WinForms program do some **specific thing** whenever a certain time-based condition is met?

How can I have a WinForms program do some specific thing whenever a certain time-based condition is met?
I was thinking I could do something with two threads, where one thread runs the normal program, and the other thread merely loops through checking if the time-based condition is true yet or not, and when the condition is true it signals an event.
However I am unsure of the best way to do it. Where in the program would I call the two threads? Maybe I am thinking about it all wrong?
How would you do this?
MORE INFO:
What it has to do is check the data.dat file and see when the last time it was updated was. If it was a month or more then do the specific thing. Could this still be done with a Timer?
NOTE:
I think it might be useful to note the difference between the System.Timers and the System.Windows.Forms.Timer...
I think you should use a Timer set to an inteligent interval to check if your time-based condition is met.
It depends what your time-based condition is. Is it a special time or an interval after which you want to do something special? If it's the second, you can just use the Timer and do what you have to do when the Timer.Elapsed event is fired.
Edit after your edit:
If you want an event to be fired every time the file changes, use a FileSystemWatcher
Edit2:
Here's the difference between System.Windows.Forms.Timer and System.Timers:
The Windows Forms Timer component is
single-threaded, and is limited to an
accuracy of 55 milliseconds. If you
require a multithreaded timer with
greater accuracy, use the Timer class
in the System.Timers namespace.
You could add a System.Windows.Forms.Timer control to your Form (see the Components category in the toolbox).
Then set the timer's interval to some value (e.g. 1000) and add a handler for its Tick event. This handler will then be called once every 1000 milliseconds.
In the handler you can then check if the conditions are met and if yes, start your specific operation.
Update (after you updated the question):
To check if the last modification of a file was more than one month ago, you can use this code:
if (File.GetLastWriteTime("data.dat").AddMonths(1) < DateTime.Now)
{
// do whatever has to be done
// if it is a time-consuming task, start a new thread!
}
You can still put this into the Tick event handler of the timer component. But in that case it does probably not make sense to fire the timer every second.
Depending on your application (e.g. if it will be started quite often), another possibility would be to execute the above check during the startup of your application.
Regarding your 'more info':
How many times must it check the modification-date of that specific file ?
Only once (during startup for instance), or should it check the modification-date of that file multiple times during application execution ?
If it has to be done only once, then it is useless to use a timer.
If it has to be done multiple times, then yes, you could use a timer.
The eventhandler of the Elapsed event could then check the ModificationDate of the file, and see if action needs to be taken.
Another solution, which is probably more elegant, is using a FileSystemWatcher.
This FileSystemWatcher could 'watch' that particalur file.
Specify a Filter on the FileSystemWatcher so that, every time the particular File is changed, an event is raised.
In the eventhandler of the FileSystemWatcher, you can then take the necessary action:
FileSystemWatcher dataFileWatcher = new FileSystemWatcher();
dataFileWatcher.Path = "path to your file";
dataFileWatcher.Filter = "yourfilename";
dataFileWatcher.Changed += new FileSystemEventHandler(OnFileChanged);
dataFileWatcher.NotifyFilter = NotifyFilters.LastWrite;
dataFileWatcher.EnableRaisingEvents = true;
private void OnFileChanged( object sender, FileSystemEventArgs e )
{
// take action.
}
Note however, that there's a sublte bug / feature in the FileSystemWatcher which causes that the Changed event gets raised multiple times for one change to the File you're watching.
You can resolve this like this
Another alternative, if you know the time between file updates (a month) is to check once at startup time. If the file is out of date you can process it immediately. If not, you can then work out how long you need to wait before checking it again. You can then schedule a task using a wait timer or other methods as described in the answers.
Basically, at startup time you can find out the limit/worst case on how long you have to wait and then you don't need to do any additional checks in the meantime. This assumes of course that the file can't be changed to an OLDER version during the running of the program which seems unlikely, but not impossible!

Categories

Resources