Creating a background timer to run asynchronously - c#

I'm really struggling with this. I'm creating a winforms application in visual studio and need a background timer that ticks once every half hour - the purpose of this is to pull down updates from a server.
I have tried a couple of different approaches but they have failed, either due to poor tutorial/examples, or to my own shortcomings in C#. I think it would be a waste of time to show you what I have tried so far as it seems what I tried was pretty far off the mark.
Does anyone know of a clear and simple way of implementing an asynchronous background timer that is easily understandable by a C# newbie?

// Create a 30 min timer
timer = new System.Timers.Timer(1800000);
// Hook up the Elapsed event for the timer.
timer.Elapsed += OnTimedEvent;
timer.Enabled = true;
...
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
// do stuff
}
with the usual caveats of: timer won't be hugely accurate and might need to GC.KeepAlive(timer)
See also: Why does a System.Timers.Timer survive GC but not System.Threading.Timer?

Declare member variable in your form:
System.Timers.Timer theTimer;
On form load (or whatever other time you need to start update polling), do:
theTimer = new System.Timers.Timer(1800000);
theTimer.Elapsed += PollUpdates;
theTimer.Start();
Declare your PollUpdates member function like this:
private void PollUpdates(object sender, EventArgs e)
{
}

I think you need to know about all timer classes. See Jon's answer below.
What kind of timer are you using?
System.Windows.Forms.Timer will execute in the UI thread
System.Timers.Timer executes in a thread-pool thread unless you
specify a SynchronizingObject
System.Threading.Timer executes its callback in a thread-pool thread
In all cases, the timer itself will be asynchronous - it won't "take up" a thread until it fires.
Source: Do .NET Timers Run Asynchronously?

Related

C# System.Timers.Timer Class elapsed event and timer general precautions

Two questions.
One: in a winforms application is it a good or bad idea to have a system.timers.timer be enabled and disabled inside of it's elapsed event so that the main UI thread can have access to variables and methods that were created on that main UI thread? So for example with code:
myElapsedTimerEvent(object sender, ElapsedEventArgs args)
{
timer.enabled = false;
/***Call some functions and manipulate some variables***/
timer.enabled = true;
}
Two: In anyone's experience, what are some precautions and dangers to be warned about the system.timers.timer in winform and c#? Are there any examples that you can provide about things that could happen with the hardware and/or software if a timer is not used properly?
Any suggestions for using system.timers.timer would be much appreciated.
Thanks for reading.
It is safe to set the Enabled property of a timer from inside the event handler, provided that the event handler is executed in the UI thread. Otherwise it is not safe, because the System.Timers.Timer class is not thread-safe. The make the handler execute in the UI thread you must set the SynchronizingObject property of the timer to the current Form. For example:
public Form1()
{
InitializeComponent();
timer = new Timers.Timer(5000);
timer.Elapsed += Timer_Elapsed;
timer.SynchronizingObject = this;
timer.AutoReset = true;
}
If I am not mistaken, this assignment happens automatically when you use the designer to add a Timer in a Form.
My suggestion though is to use the System.Windows.Forms.Timer, because it comes without thread-safety considerations. You are not restricted to only one timer. You can have as many of them as you want. Just keep in mind that their handlers are running in the UI thread, so you should avoid putting lengthy code in there, otherwise the responsiveness of the UI may suffer.

System.Windows.Forms.Timer not firing

I want to use a System.Windows.Forms.Timer to ensure that an event fires on the UI thread of an excel addin I'm creating. I construct the timer as follows:
private System.Windows.Forms.Timer _timer;
private void ThisAddIn_Startup(object sender, System.EventArgs e)
{
Debug.WriteLine("ThisAddIn_Startup:" + Thread.CurrentThread.ManagedThreadId);
_timer = new System.Windows.Forms.Timer();
_timer.Tick += new EventHandler(TimerEventHandler);
_timer.Interval = 500;
}
The timer is fired by a COM event from a library I am using:
private void OnEvent()
{
_timer.Start();
}
I then expect the _timer to call the following method when it ticks:
public void TimerEventHandler(object sender, EventArgs args)
{
_timer.Stop();
Debug.WriteLine("Tick: " + Thread.CurrentThread.ManagedThreadId);
}
As I understand, when I create the timer in the Addin thread, even though it is started from another thread (COM event in this case), it should fire on the thread that it was created on, i.e. the addin thread. However, this doesn't happen.
I have implemented this exact mechanism in an RTDServer I wrote in the past (as outlined by Kenny Kerr) and it works as expected but the _timer in this scenario never ticks.
I have also read other SO articles that point to the same behavior and can't figure out what is different about my addin setup?
EDIT:
The OnEvent() method is fired.
The winforms timer is a control and must be used by placing it on a form. You never add it to a control-collection, so I would not expect it to work properly. The documentation says the following
Implements a timer that raises an event at user-defined intervals. This timer is optimized for use in Windows Forms applications and must be used in a window.
Therefore, I would suggest that you use an instance of the System.Timers.Timer class. This class can be used anywhere.
Note that the Tick-event you use above, is called by another name in the System.Timer.Timer class, namely the Elapsed-event.
I initially meant to post this as comment, but it turned to be too long.
Firstly, your thread structure is a bit confusing to me, the way you described it. Put Debug.WriteLine("OnEvent:" + Thread.CurrentThread.ManagedThreadId) inside OnEvent and let us know all thread IDs you see from your debug output.
That said, the rules are:
You should create WinForms' Timer object on an STA thread, and the thread should be configured as STA before it starts.
This thread may or may not be the main UI thread (where your main form was created), but it still should execute a message loop (with Application.Run) for timer events to fire. There are other ways of pumping messages, but generally you do not control them from .NET code.
You should handle the events sourced by WinForms' Timer on the same thread it was created. You can then 'forward' these events to another thread context if you like (using SynchronizationContext Send or Post) but I can't think of any reasons for such complexity.
The answer by #Maarten actually suggests the right way of doing it, in my opinion.
I don't yet understand why the Forms.Timer doesn't operate as expected but the following excellent article explains in detail how to marshal work onto the UI thread: http://www.codeproject.com/Articles/31971/Understanding-SynchronizationContext-Part-I

How to trigger an event for the given interval of time repeatedly in c#?

How to schedule the event, for instance I need to call a method which should perform its action for every given seconds. I'm developing simple windows form app, I tried using like
while(true)
{
methodToBeScheduled();
Thread.Sleep(60000);
}
This particular piece of code makes my application "Not-responding" while its executing. I hope timer can do this or any other logic that you experts suggest, kindly please let me know.
Thanks!
You can use the WinForms timer:
Timer _timer;
// In constructor (or anywhere you want to start the timer, e.g. a button event):
_timer = new Timer();
_timer.Interval = 60000; // milliseconds
_timer.Tick += (sender, e) => methodToBeScheduled();
_timer.Start();
This will cause methodToBeScheduled to be called once every 60 seconds, roughly. It will be called on the main UI thread, so avoid doing any heavy processing in it.
The advantage of using this timer is that it's built-in, doesn't require thread synchronization, and is simple to use. The disadvantage is that the interval is not exact -- the actual interval will vary depending on what other messages need to be processed in the application, and is also at the mercy of the Windows system clock, which is only accurate to 10-20ms or so.
You can use a Timer(System.Threading.Timer).
using System;
using System.Threading;
Timer _timer = null;
_timer = new Timer(o =>
{
methodToBeScheduled();
});
_timer.Change(TimeSpan.Zero, TimeSpan.FromSeconds(60));
Var sequence = Observable.interval(1).publish
Sequence.subscribe ....
Will allow to subscribe to an observable that will fire an onnext every second. See reactive extension ..
Hate typing on iPads....
Yes, there are three different types of timers (all of which are named Timer but behave a little different) in .net. The windows.forms timer executes a function at a certain rate--it calls the function from the UI thread. The System.Threading Timer does the same but calls the function from another thread. There is another timer that I can't remember off the top of my head. You will have to pick one of them based on your circumstance.
Threading timer is my favorite. Here is an example if how to use it. Just keep in mind whatever you are calling is not done from the UI thread. May want to use the forms timer or synchronize things if that's an issue.

overlooping in C#

I am going to create a system service in C#.
In the onstart section I would like to loop every 30 seconds and query a mysql database. If numrows are greater than 0 I will process some faxes using the faxcom library.
My question is: Would looping every 30 seconds exhaust the program/computer? What would be the best function/method to use for the loop and sleep? Do you have any example code for the loop and sleep?
Using Thread.Sleep() would be a bad solution, because even while sleeping your thread is active. Use Timer class instead and handle its Elapsed event.
This article examines different ways to tackle the periodical execution of your service.
Here is what your OnStart method might look like:
using System.Timers;
private timer = new Timer();
protected override void OnStart(string[] args)
{
timer.Elapsed += new ElapsedEventHandler(OnElapsedTime);
timer.Interval = 30000; // every 30 seconds
timer.Enabled = true;
}
Private void OnElapsedTime(object source, ElapsedEventArgs e)
{
// Execute your code here
}
I wouldn't use looping constructs for such a thing.
I would use one of the timer controls in the BCL and set it to fire every 30 seconds.
As for the question of if this is "too much", the answer entirely depends on the amount of work being done and the load it generates.
No, you would not be using the CPU, because sleeping threads are not scheduled for execution until their sleep time expires. Use Thread.Sleep to make the current thread sleep for timeout miliseconds. Something like:
while(!stop) // boolean variable to indicate when to stop the service.
{
Thread.Sleep(30000);
// do work
}
You will, of course, need to run this on a separate thread, otherwise you will block the main thread.
I would avoid using System.Timers.Timer in your case solely because you are writing a Windows Service. While you can use it, you won't have a GUI available and therefore don't need anything that this timer would expose as if you were using a GUI (it inherits from System.ComponentModel.Component for this reason). It's pretty simple
to use.

Timer on Wallpaper Cycler

I just added some extra functionality to a Coding4Fun project. I have my project set up with an extra option to allow it to automatically change the background after X amount of time. X is set from a ComboBox. However, I know I've done this in a terrible way, as I have created a new timer class with System.Timers.Timer as a parent so when the static method in the ElapsedEventHandler is called, I'm able to get back to the form and call ChangeDesktopBackground().
What is a better way to call ChangeDesktopBackground() at a user defined interval?
Here is my current solution, which involves me casting the sender as my inherited timer, which then gets a reference to the form, which then calls the ChangeDesktopBackground method.
private static void timerEvent(object sender, System.Timers.ElapsedEventArgs e)
{
((newTimer)sender).getCycleSettingsForm().ChangeDesktopBackground();
}
Edit:Added coding sample to show current solution
I've written something like this before myself. System.Timers.Timer is overkill for this. You should probably use System.Windows.Forms.Timer, for a couple of reasons:
You're doing something that doesn't have to be too precise. The Windows timer is just a WM_TIMER message sent to your windows app's message pump, so you're not getting super great precision, but changing your wallpaper once a second is unrealistic. (I wrote mine to change every 6 hours or so)
When using a Windows Forms app that does some kind of timer-based task, you're going to run into all kinds of thread affinity issues if you go with System.Timers.Timer. Any Windows control has an affinity for the thread on which it was created, meaning that you can only modify the control on that thread. A Windows.Forms.Timer will do all that stuff for you. (For future nitpickers, changing wallpaper doesn't really count, cause it's a registry value change, but the rule holds generally)
Timers are probably the most straight-forward way of doing it, although I'm not sure you're using a timer correctly. Here's how I've used timers in my projects:
// here we declare the timer that this class will use.
private Timer timer;
//I've shown the timer creation inside the constructor of a main form,
//but it may be done elsewhere depending on your needs
public Main()
{
// other init stuff omitted
timer = new Timer();
timer.Interval = 10000; // 10 seconds between images
timer.Tick += timer_Tick; // attach the event handler (defined below)
}
void timer_Tick(object sender, EventArgs e)
{
// this is where you'd show your next image
}
Then, you'd connect your ComboBox onChange handler such that you'd be changing timer.Interval.
I would use Microsoft's Reactive Framework for this. Just NuGet "Rx-WinForms".
Here's the code:
var subscription =
Observable
.Interval(TimeSpan.FromMinutes(1.0))
.ObserveOn(this)
.Subscribe(n => this.getCycleSettingsForm().ChangeDesktopBackground());
To stop it just do subscription.Dispose().
Simple.

Categories

Resources