prevent this unsafe cross threading - c#

I have this code:
private void Form1_Load(object sender, EventArgs e)
{
/*start update timer*/
System.Timers.Timer updateticker = new System.Timers.Timer();
updateticker.Elapsed += new ElapsedEventHandler(update_overload);
//10 minute ticker
updateticker.Interval = 600000;
//30 sec ticker
updateticker.Interval = 30000;
updateticker.Enabled = true;
System.Timers.Timer guiTimer = new System.Timers.Timer();
guiTimer.Elapsed += new ElapsedEventHandler(idle_display);
//1 minute ticker
guiTimer.Interval = 60000;
//30 sec ticker
//updateticker.Interval = 30000;
guiTimer.Enabled = true;
}
//run front end idle timer
public void idle_display(object source, ElapsedEventArgs e)
{
if (minutes_left > 0) {
minutes_left = minutes_left - 1;
}
lbl_dyn_status.Text = "Time until next automatic update: "+ minutes_left + " minutes.";
}
Visual studio is flagging the final line of the second function as unsafe cross threading. Can anyone suggest how I rewrite this to solve the issue?
Cheers

Use System.Windows.Forms.Timer instead of System.Timers.Timer
or use SynchronizingObject property of Timer.
When SynchronizingObject is null, the method that handles the Elapsed event is called on a thread from the system-thread pool. For more information on system-thread pools, see ThreadPool.
When the Elapsed event is handled by a visual Windows Forms component, such as a button, accessing the component through the system-thread pool might result in an exception or just might not work. Avoid this effect by setting SynchronizingObject to a Windows Forms component, which causes the method that handles the Elapsed event to be called on the same thread that the component was created on.

As others suggested, use System.Windows.Forms.Timer. Unlike System.Threading.Timer, which operates on Thread Pool threads, it guarantees you that the tick event is invoked on the UI thread.
The UI thread is the only thread allows to modify the UI. This is why you get an exception trying to write lbl_dyn_status.Text.

Use System.Windows.Forms.Timer timer instead of System.Timers.Timer.

Change the handler to
public void IdleDisplay(object source, ElapsedEventArgs e)
{
if (lbl_dyn_status.InvokeRequired)
{
this.Invoke(IdleDisplay)
}
else
{
if (minutes_left > 0)
{
minutes_left = minutes_left - 1;
}
lbl_dyn_status.Text = string.Format(
"Time until next automatic update: {0} minutes.",
minutes_left);
}
}
This way allows you to use the thread free System.Threading.Timer but checks for a cross-thread call in the handler. If detected the call is invoked on the main GUI thread, via the Form class.
This is described on MSDN in more detail here.
More generally, you should not use timers to count time like this. The more thread bound your timer is, the more it is likely to diverge from real elapsed time. You can use your timer to schedule an update of your clock but, you should calculate elapsed time since some fixed point rather than using an iterative counter.

Related

Timer kills task/job if it runs longer than timer interval

I would to make a timer which behaviour is like this:
if processing time of task/job is less than timer interval, start timer in (timer.interval - processing time job/job)
if processing time of job/task is more than timer interval, start next job/task immediatly
Code below works but I would like to know why in the ElapsedEventHandler method job/task must be first done and then we can set new timer interval. Elapsed event of System.Timers.Timer is raised when interval has elapsed. With the option AutoReset = false we set that the Timer raises the Elapsed event only once, after the first Interval has elapsed. We have to then manually call Timer.Start() to start it again.
using System;
using System.Timers;
namespace TestTimer
{
class Program
{
private static Timer t;
private static double intervalMiliseconds;
static void Main(string[] args)
{
intervalMiliseconds = 5000; // 5 seconds
t = new Timer();
t.Interval = intervalMiliseconds;
t.AutoReset = false;
t.Elapsed += new ElapsedEventHandler(OnTimedEvent);
t.Start();
log("Timer started at " + DateTime.Now.ToString());
log("Interval is: " + defaultIntervalMiliseconds);
Console.ReadKey();
}
private static void log(string text)
{
Console.WriteLine(text + "\n");
}
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
// if t.Interval is set here thread just kills the job if it
// runs longer than interval
t.Interval = intervalMiliseconds;
log("ElapsedEvent triggered at " + DateTime.Now.ToString());
// job
DateTime startTime = DateTime.Now;
log("job started" );
System.Threading.Thread.Sleep(8000); // 8 sec
log("job ended" );
TimeSpan jobTime = DateTime.Now.Subtract(startTime);
log("job took " + jobTime.TotalSeconds + " seconds");
// if we set t.Interval here it works so first the job
// must be done and than we can set timer interval ? why ?
//t.Interval = intervalMiliseconds;
if (jobTime.TotalMilliseconds < t.Interval)
{
t.Interval = t.Interval - jobTime.TotalMilliseconds;
log("Job ended Earlier starting Event in: " + t.Interval);
}
else
{
t.Interval = 100;
log("Job overpass interval. Current time: " +
DateTime.Now.ToString());
}
t.AutoReset = false;
t.Start();
}
}
}
Result of this:
If we comment t.Interval at the start of method OnTimedEvent and uncomment t.Interval after the job has done everything works. Result of this:
Why we can not set timer interval at the start of method OnTimedEvent. If we do if the task/job runs longer than the timer interval, thread just kills the job. I would really appreciate if anyone has some ideas? Does this have to do with synhronization of thread with main thread (which timer runs)? When we call method OnTimedEvent the timer will not call that method again because it has AutoReset = false, what difference does it make where we set timer properties?
t.Interval = intervalMiliseconds;
That's indeed the troublemaker. It is pretty unintuitive behavior, one that the MSDN article for Timer.Interval specifically warns about in a Note:
If Enabled and AutoReset are both set to false, and the timer has previously been enabled, setting the Interval property causes the Elapsed event to be raised once, as if the Enabled property had been set to true. To set the interval without raising the event, you can temporarily set the AutoReset property to true.
It's a fairly silly hack but does work. Just delaying assigning the value is certainly the better way to do it. Doing it early doesn't buy you anything, other than trouble, the timer isn't going tick anyway since you've got AutoReset = false.
System.Threading.Timer is the better timer class with many fewer quirks. It for one doesn't swallow exceptions without any diagnostic in the callback method. Which your code is quite sensitive to, the timer will just stop ticking since the exception bypasses the t.Start() call and you'll have no idea why. Strongly recommended.
!! No and never Timer kill task/job if it runs longer than timer interval !!
if processing time of task/job is less than timer interval,
after timer interval/span.
if processing time of job/task is more than timer interval,
start next job/task after timer interval/span into a new Thread.
so for minimizing idle time you should keep timer interval small.
In System.Timers.Timer class internally already Threading Implemented. so don`t need to implements threading.

timer on thread?

Can i create successfully a timer clock on a thread? i'm creating one but it doesn't seem to work that well. My app is a multi-thread app that has to start a timer on a thread when ever a certain event happens. The timer is placed in every client connection. The clock doesn't work until i close my winform(i don't know why) . Is there anything in particular that i should know about timers in threads ?
Here is my timer code :
timer1.Interval = 1000;
timer1.Tick += new EventHandler(timer_Tick);
timer1.Enabled = true;
timer1.Start();
You might try to use System.Threading.Timer, which is basically a timer that's in a separate thread. You might also consider using a WaitHandle that's never fired and then using WaitOne(1000, false) to wait for a second.
Try this:
public void EnableTimer()
{
if (this.InvokeRequired)
this.Invoke(new Action(EnableTimer));
else
this.timer1.Enabled = true;
}

Do C# Timers elapse on a separate thread?

Does a System.Timers.Timer elapse on a separate thread than the thread that created it?
Lets say I have a class with a timer that fires every 5 seconds. When the timer fires, in the elapsed method, some object is modified. Lets say it takes a long time to modify this object, like 10 seconds. Is it possible that I will run into thread collisions in this scenario?
It depends. The System.Timers.Timer has two modes of operation.
If SynchronizingObject is set to an ISynchronizeInvoke instance then the Elapsed event will execute on the thread hosting the synchronizing object. Usually these ISynchronizeInvoke instances are none other than plain old Control and Form instances that we are all familiar with. So in that case the Elapsed event is invoked on the UI thread and it behaves similar to the System.Windows.Forms.Timer. Otherwise, it really depends on the specific ISynchronizeInvoke instance that was used.
If SynchronizingObject is null then the Elapsed event is invoked on a ThreadPool thread and it behaves similar to the System.Threading.Timer. In fact, it actually uses a System.Threading.Timer behind the scenes and does the marshaling operation after it receives the timer callback if needed.
For System.Timers.Timer:
See Brian Gideon's answer below
For System.Threading.Timer:
MSDN Documentation on Timers states:
The System.Threading.Timer class makes
callbacks on a ThreadPool thread and
does not use the event model at all.
So indeed the timer elapses on a different thread.
Each elapsed event will fire in the same thread unless a previous Elapsed is still running.
So it handles the collision for you
try putting this in a console
static void Main(string[] args)
{
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
var timer = new Timer(1000);
timer.Elapsed += timer_Elapsed;
timer.Start();
Console.ReadLine();
}
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
Thread.Sleep(2000);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
you will get something like this
10
6
12
6
12
where 10 is the calling thread and 6 and 12 are firing from the bg elapsed event.
If you remove the Thread.Sleep(2000); you will get something like this
10
6
6
6
6
Since there are no collisions.
But this still leaves u with a problem. if u are firing the event every 5 seconds and it takes 10 seconds to edit u need some locking to skip some edits.
For System.Timers.Timer, on separate thread, if SynchronizingObject is not set.
static System.Timers.Timer DummyTimer = null;
static void Main(string[] args)
{
try
{
Console.WriteLine("Main Thread Id: " + System.Threading.Thread.CurrentThread.ManagedThreadId);
DummyTimer = new System.Timers.Timer(1000 * 5); // 5 sec interval
DummyTimer.Enabled = true;
DummyTimer.Elapsed += new System.Timers.ElapsedEventHandler(OnDummyTimerFired);
DummyTimer.AutoReset = true;
DummyTimer.Start();
Console.WriteLine("Hit any key to exit");
Console.ReadLine();
}
catch (Exception Ex)
{
Console.WriteLine(Ex.Message);
}
return;
}
static void OnDummyTimerFired(object Sender, System.Timers.ElapsedEventArgs e)
{
Console.WriteLine(System.Threading.Thread.CurrentThread.ManagedThreadId);
return;
}
Output you'd see if DummyTimer fired on 5 seconds interval:
Main Thread Id: 9
12
12
12
12
12
...
So, as seen, OnDummyTimerFired is executed on Workers thread.
No, further complication - If you reduce interval to say 10 ms,
Main Thread Id: 9
11
13
12
22
17
...
This is because if prev execution of OnDummyTimerFired isn't done when next tick is fired, then .NET would create a new thread to do this job.
Complicating things further, "The System.Timers.Timer class provides an easy way to deal with this dilemma—it exposes a public SynchronizingObject property. Setting this property to an instance of a Windows Form (or a control on a Windows Form) will ensure that the code in your Elapsed event handler runs on the same thread on which the SynchronizingObject was instantiated."
http://msdn.microsoft.com/en-us/magazine/cc164015.aspx#S2
If the elapsed event takes longer then the interval, it will create another thread to raise the elapsed event. But there is a workaround for this
static void timer_Elapsed(object sender, ElapsedEventArgs e)
{
try
{
timer.Stop();
Thread.Sleep(2000);
Debug.WriteLine(Thread.CurrentThread.ManagedThreadId);
}
finally
{
timer.Start();
}
}

How to reset a timer in C#?

There are three Timer classes that I am aware of, System.Threading.Timer, System.Timers.Timer, and System.Windows.Forms.Timer, but none of these have a .Reset() function which would reset the current elapsed time to 0.
Is there a BCL class that has this functionality? Is there a non-hack way of doing it? (I thought perhaps changing the time limit on it might reset it) Thought on how hard it would be to reimplement a Timer class that had this functionality, or how to do it reliably with one of the BCL classes?
I always do ...
myTimer.Stop();
myTimer.Start();
... is that a hack? :)
Per comment, on Threading.Timer, it's the Change method ...
dueTime Type: System.Int32 The
amount of time to delay before the
invoking the callback method specified
when the Timer was constructed, in
milliseconds. Specify
Timeout.Infinite to prevent the
timer from restarting. Specify zero
(0) to restart the timer immediately.
All the timers have the equivalent of Start() and Stop() methods, except System.Threading.Timer.
So an extension method such as...
public static void Reset(this Timer timer)
{
timer.Stop();
timer.Start();
}
...is one way to go about it.
For System.Timers.Timer, according to MSDN documentation, http://msdn.microsoft.com/en-us/library/system.timers.timer.enabled.aspx:
If the interval is set after the Timer has started, the count is
reset. For example, if you set the interval to 5 seconds and then set
the Enabled property to true, the count starts at the time Enabled is
set. If you reset the interval to 10 seconds when count is 3 seconds,
the Elapsed event is raised for the first time 13 seconds after
Enabled was set to true.
So,
const double TIMEOUT = 5000; // milliseconds
aTimer = new System.Timers.Timer(TIMEOUT);
aTimer.Start(); // timer start running
:
:
aTimer.Interval = TIMEOUT; // restart the timer
You could write an extension method called Reset(), which
calls Stop()-Start() for Timers.Timer and Forms.Timer
calls Change for Threading.Timer
I just assigned a new value to the timer:
mytimer.Change(10000, 0); // reset to 10 seconds
It works fine for me.
at the top of the code define the timer: System.Threading.Timer myTimer;
if (!active)
myTimer = new Timer(new TimerCallback(TimerProc));
myTimer.Change(10000, 0);
active = true;
private void TimerProc(object state)
{
// The state object is the Timer object.
var t = (Timer)state;
t.Dispose();
Console.WriteLine("The timer callback executes.");
active = false;
// Action to do when timer is back to zero
}
For a Timer (System.Windows.Forms.Timer).
The .Stop, then .Start methods worked as a reset.
You can do timer.Interval = timer.Interval
I do the following.
Disposing the timer and initializing it again.
But this will erase any event you attached to this timer.
timer.Dispose();
timer = new System.Timers.Timer();
Other alternative way to reset the windows.timer is using the counter, as follows:
int timerCtr = 0;
Timer mTimer;
private void ResetTimer() => timerCtr = 0;
private void mTimer_Tick()
{
timerCtr++;
// Perform task
}
So if you intend to repeat every 1 second, you can set the timer interval at 100ms, and test the counter to 10 cycles.
This is suitable if the timer should wait for some processes those may be ended at the different time span.
i do this
//Restart the timer
queueTimer.Enabled = true;

Best Timer for using in a Windows service

Locked. This question and its answers are locked because the question is off-topic but has historical significance. It is not currently accepting new answers or interactions.
I need to create some windows service which will execute every N period of time.
The question is:
Which timer control should I use: System.Timers.Timer or System.Threading.Timer one? Does it influence on something?
I am asking because I heard many evidences to non correct work of System.Timers.Timer in windows services.
Thank you.
Both System.Timers.Timer and System.Threading.Timer will work for services.
The timers you want to avoid are System.Web.UI.Timer and System.Windows.Forms.Timer, which are respectively for ASP applications and WinForms. Using those will cause the service to load an additional assembly which is not really needed for the type of application you are building.
Use System.Timers.Timer like the following example (also, make sure that you use a class level variable to prevent garbage collection, as stated in Tim Robinson's answer):
using System;
using System.Timers;
public class Timer1
{
private static System.Timers.Timer aTimer;
public static void Main()
{
// Normally, the timer is declared at the class level,
// so that it stays in scope as long as it is needed.
// If the timer is declared in a long-running method,
// KeepAlive must be used to prevent the JIT compiler
// from allowing aggressive garbage collection to occur
// before the method ends. (See end of method.)
//System.Timers.Timer aTimer;
// Create a timer with a ten second interval.
aTimer = new System.Timers.Timer(10000);
// Hook up the Elapsed event for the timer.
aTimer.Elapsed += new ElapsedEventHandler(OnTimedEvent);
// Set the Interval to 2 seconds (2000 milliseconds).
aTimer.Interval = 2000;
aTimer.Enabled = true;
Console.WriteLine("Press the Enter key to exit the program.");
Console.ReadLine();
// If the timer is declared in a long-running method, use
// KeepAlive to prevent garbage collection from occurring
// before the method ends.
//GC.KeepAlive(aTimer);
}
// Specify what you want to happen when the Elapsed event is
// raised.
private static void OnTimedEvent(object source, ElapsedEventArgs e)
{
Console.WriteLine("The Elapsed event was raised at {0}", e.SignalTime);
}
}
/* This code example produces output similar to the following:
Press the Enter key to exit the program.
The Elapsed event was raised at 5/20/2007 8:42:27 PM
The Elapsed event was raised at 5/20/2007 8:42:29 PM
The Elapsed event was raised at 5/20/2007 8:42:31 PM
...
*/
If you choose System.Threading.Timer, you can use as follows:
using System;
using System.Threading;
class TimerExample
{
static void Main()
{
AutoResetEvent autoEvent = new AutoResetEvent(false);
StatusChecker statusChecker = new StatusChecker(10);
// Create the delegate that invokes methods for the timer.
TimerCallback timerDelegate =
new TimerCallback(statusChecker.CheckStatus);
// Create a timer that signals the delegate to invoke
// CheckStatus after one second, and every 1/4 second
// thereafter.
Console.WriteLine("{0} Creating timer.\n",
DateTime.Now.ToString("h:mm:ss.fff"));
Timer stateTimer =
new Timer(timerDelegate, autoEvent, 1000, 250);
// When autoEvent signals, change the period to every
// 1/2 second.
autoEvent.WaitOne(5000, false);
stateTimer.Change(0, 500);
Console.WriteLine("\nChanging period.\n");
// When autoEvent signals the second time, dispose of
// the timer.
autoEvent.WaitOne(5000, false);
stateTimer.Dispose();
Console.WriteLine("\nDestroying timer.");
}
}
class StatusChecker
{
int invokeCount, maxCount;
public StatusChecker(int count)
{
invokeCount = 0;
maxCount = count;
}
// This method is called by the timer delegate.
public void CheckStatus(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
Console.WriteLine("{0} Checking status {1,2}.",
DateTime.Now.ToString("h:mm:ss.fff"),
(++invokeCount).ToString());
if(invokeCount == maxCount)
{
// Reset the counter and signal Main.
invokeCount = 0;
autoEvent.Set();
}
}
}
Both examples comes from the MSDN pages.
Don't use a service for this. Create a normal application and create a scheduled task to run it.
This is the commonly held best practice. Jon Galloway agrees with me. Or maybe its the other way around. Either way, the fact is that it is not best practices to create a windows service to perform an intermittent task run off a timer.
"If you're writing a Windows Service that runs a timer, you should re-evaluate your solution."
–Jon Galloway, ASP.NET MVC community program manager, author, part time superhero
Either one should work OK. In fact, System.Threading.Timer uses System.Timers.Timer internally.
Having said that, it's easy to misuse System.Timers.Timer. If you don't store the Timer object in a variable somewhere, then it is liable to be garbage collected. If that happens, your timer will no longer fire. Call the Dispose method to stop the timer, or use the System.Threading.Timer class, which is a slightly nicer wrapper.
What problems have you seen so far?
I agree with previous comment that might be best to consider a different approach. My suggest would be write a console application and use the windows scheduler:
This will:
Reduce plumbing code that replicates scheduler behaviour
Provide greater flexibility in terms
of scheduling behaviour (e.g. only
run on weekends) with all scheduling logic abstracted from application code
Utilise the command line arguments
for parameters without having to
setup configuration values in config
files etc
Far easier to debug/test during development
Allow a support user to execute by invoking
the console application directly
(e.g. useful during support
situations)
As already stated both System.Threading.Timer and System.Timers.Timer will work. The big difference between the two is that System.Threading.Timer is a wrapper arround the other one.
System.Threading.Timer will have more exception handling while
System.Timers.Timer will swallow all the exceptions.
This gave me big problems in the past so I would always use 'System.Threading.Timer' and still handle your exceptions very well.
I know this thread is a little old but it came in handy for a specific scenario I had and I thought it worth while to note that there is another reason why System.Threading.Timer might be a good approach.
When you have to periodically execute a Job that might take a long time and you want to ensure that the entire waiting period is used between jobs or if you don't want the job to run again before the previous job has finished in the case where the job takes longer than the timer period.
You could use the following:
using System;
using System.ServiceProcess;
using System.Threading;
public partial class TimerExampleService : ServiceBase
{
private AutoResetEvent AutoEventInstance { get; set; }
private StatusChecker StatusCheckerInstance { get; set; }
private Timer StateTimer { get; set; }
public int TimerInterval { get; set; }
public CaseIndexingService()
{
InitializeComponent();
TimerInterval = 300000;
}
protected override void OnStart(string[] args)
{
AutoEventInstance = new AutoResetEvent(false);
StatusCheckerInstance = new StatusChecker();
// Create the delegate that invokes methods for the timer.
TimerCallback timerDelegate =
new TimerCallback(StatusCheckerInstance.CheckStatus);
// Create a timer that signals the delegate to invoke
// 1.CheckStatus immediately,
// 2.Wait until the job is finished,
// 3.then wait 5 minutes before executing again.
// 4.Repeat from point 2.
Console.WriteLine("{0} Creating timer.\n",
DateTime.Now.ToString("h:mm:ss.fff"));
//Start Immediately but don't run again.
StateTimer = new Timer(timerDelegate, AutoEventInstance, 0, Timeout.Infinite);
while (StateTimer != null)
{
//Wait until the job is done
AutoEventInstance.WaitOne();
//Wait for 5 minutes before starting the job again.
StateTimer.Change(TimerInterval, Timeout.Infinite);
}
//If the Job somehow takes longer than 5 minutes to complete then it wont matter because we will always wait another 5 minutes before running again.
}
protected override void OnStop()
{
StateTimer.Dispose();
}
}
class StatusChecker
{
public StatusChecker()
{
}
// This method is called by the timer delegate.
public void CheckStatus(Object stateInfo)
{
AutoResetEvent autoEvent = (AutoResetEvent)stateInfo;
Console.WriteLine("{0} Start Checking status.",
DateTime.Now.ToString("h:mm:ss.fff"));
//This job takes time to run. For example purposes, I put a delay in here.
int milliseconds = 5000;
Thread.Sleep(milliseconds);
//Job is now done running and the timer can now be reset to wait for the next interval
Console.WriteLine("{0} Done Checking status.",
DateTime.Now.ToString("h:mm:ss.fff"));
autoEvent.Set();
}
}

Categories

Resources