In general it's good practice to garbage collect as it frees up resources.
How do I implement correct garbage collection in the following code's keepingTime method? Or, in fact, do I even need to?!
System.Timers.Timer allows IDisposable interface so 'using' is an option, but not in the following as the scope of the timer needs to extend to the method myTimer_Elapsed that is subscribed to the Timer Elapsed event. I've made two attempts to garbage collect but both fail as the timer does not then hang around long enough!
I've previously dicussed this code, for other reasons, in HERE
public partial class AirportParking : Form
{
//>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
//instance variables of the form
System.Timers.Timer myTimer;
private const string EvenText = "hello";
private const string OddText = "hello world";
static int tickLength = 100;
static int elapsedCounter;
private int MaxTime = 5000;
private TimeSpan elapsedTime;
private readonly DateTime startTime = DateTime.Now;
//<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
public AirportParking()
{
InitializeComponent();
lblValue.Text = EvenText;
keepingTime();
}
//method for keeping time
public void keepingTime() {
myTimer = new System.Timers.Timer(tickLength);
myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);
myTimer.AutoReset = true;
myTimer.Enabled = true;
myTimer.Start();
//ATTEMPT_1.tried the following unsuccessfully
//using (System.Timers.Timer myTimer = new System.Timers.Timer(tickLength))
//{
// myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);
// myTimer.AutoReset = true;
// myTimer.Enabled = true;
// myTimer.Start();
//}
//ATTEMPT_2.tried the following unsuccessfully
//myTimer.Elapsed += new ElapsedEventHandler(myTimer_Elapsed);
//myTimer.AutoReset = true;
//myTimer.Enabled = true;
//try
//{
// myTimer.Start();
//}
//finally
//{
// myTimer.Dispose();
//}
}
private void myTimer_Elapsed(Object myObject,EventArgs myEventArgs){
elapsedCounter++;
elapsedTime = DateTime.Now.Subtract(startTime);
if (elapsedTime.TotalMilliseconds < MaxTime)
{
this.BeginInvoke(new MethodInvoker(delegate
{
this.lblElapsedTime.Text = elapsedTime.ToString();
if (elapsedCounter % 2 == 0)
this.lblValue.Text = EvenText;
else
this.lblValue.Text = OddText;
}));
}
else {myTimer.Stop();}
}
}
The only place you'll want to dispose of the timer resource is in the callback function myTimer_Elapsed. Where you do myTime.Stop(); you can also do myTimer.Dispose();.
However, when this part of the application goes out of scope, all these variables will be cleaned up anyway. As long as the timer is eventually stopped, once it's dereferenced it will be collected by the GC.
The reason the using blocks (and your current Dispose()) doesn't work is that you're throwing away the timer as soon as you create it! You have to let it run in the background.
Dispose your timer on Form's OnClosing event, if this is not a main form, or by the way, a Form that always visible.
A pseudocode can look like this:
public partial class AirportParking : Form
{
.....
.....
protected override void OnClosing(...)
{
myTimer.Dispose();
}
}
If this is some "long-running" form, you should add disposal of the timere at the moment you no more need it, but I think you already know that.
Although it is good practice to garbage collect, in this instance it would be would be done automatically when you close the form or the instance dies.
The only time I really worry about this is with SQL readers as you have to make sure they are closed off when you are finished otherwise it causes all sorts of problems.
Related
Here's my situation:
I have a WPF application, where I have a method which takes a lot of time to be completed. I don't want to lose UI responsiveness, so I'd like to call that method in another thread.
I won't paste here my entire code, because it's too long, instead I wrote this short program, which represents well what I'm dealing with:
public void MainWindow()
{
InitializeComponent();
ProcessThread = new Thread(TimeConsumingMethod);
ProcessThread.Name = "ProcessThread";
ProcessThread.Start();
}
public void TimeConsumingMethod()
{
this.Dispatcher.Invoke(() =>
{
MytextBlock.Text = "new text";
MyOtherTextBlock.Text = "Hello";
});
for (int i = 0; i < 50; i++)
{
Debug.WriteLine("Debug line " + i);
}
if (MyRadioButton.IsChecked == false) //????????????????
{
while (true)
{
if (DateTime.Now >= timePicker.Value)
break;
}
}
OtherMethod();
}
Actually, I have two questions for the above code:
1. Everytime I want to access UI controls in my code I have to use this.Dispatcher.Invoke() =>.... Is it the right thing to do? I mean, I have a few places in my method (in my real code) where I check the state of some controls and everytime I need to do his Dispatcher.invoke thing - isn't there a better way to acces these controls?
2. In the code above, there's IF block in the end - in that block I'm checking the state of my RadioButton. Inside of that IF, I have a time consuming code. I cannot just do this:
this.Dispatcher.Invoke(() =>
{
if (MyRadioButton.IsChecked == false) //????????????????
{
while (true)
{
if (DateTime.Now >= timePicker.Value)
break;
}
}
});
That code would tell my UI thread to handle this if block - but I don't want that! That would cause the whole UI to freeze until this IF block gets done. How should I handle this situation?
Well, there are a lot of ways to implement what you are trying to do. One of them might look like this:
public MainWindow() {
InitializeComponent();
Initialize(); //do some intialization
}
private async void Timer_Tick(object sender, EventArgs e) {
if (DateTime.Now >= timePicker.SelectedDate) { //check your condition
timer.Stop(); //probably you need to run it just once
await Task.Run(() => OtherMethod()); //instead of creating thread manually use Thread from ThreadPool
//use async method to avoid blocking UI during long method is running
}
}
private readonly DispatcherTimer timer = new DispatcherTimer(); //create a dispatcher timer that will execute code on UI thread
public void Initialize() {
MytextBlock.Text = "new text";
MyOtherTextBlock.Text = "Hello"; //access UI elements normally
for (var i = 0; i < 50; i++) {
Debug.WriteLine("Debug line " + i);
}
if (MyRadioButton.IsChecked == false)
{
timer.Interval = TimeSpan.FromSeconds(10); // during init setup timer instead of while loop
timer.IsEnabled = true;
timer.Tick += Timer_Tick; //when 10 sec pass, this method is called
timer.Start();
}
}
public void OtherMethod() {
//long running method
Thread.Sleep(1000);
}
I've added some comments, but the main idea is this:
Don't create threads manually, use ThreadPool
Don't loop to wait for something, use timer to periodically check for it
Use async method when you have I/O Tasks
I'm having trouble with the following code. I have some code that calls SetTimer() and expects the user to respond before interval is reached (in
millisecs). The calling code inherit these funtions. If the user responds, then StopTimer() is called, info is displayed, StartTimer() is called, and the user is expected to respond again within the interval time period. This continues until the user fails in an answer or takes too long (goes past the interval).
The problem is the timers don't stop. They keep repeating even after I've stopped them, set their Tick event to null (by the -= method), and left its scope. I even get new storage with a new DispatcherTimer (I've done this both using the old one and a new one each time). I can't get the old Timer to go away.
What am I doing wrong?
using Windows.UI.XAML;
public DispatcherTimer GameTimer;
internal void SetTimer(int interval)
{
GameTimer = new DispatcherTimer();
GameTimer.Tick += TimerCallback;
GameTimer.Interval = new TimeSpan(0,0,0,0,interval);
GameTimer.Start();
}
internal void StopTimer()
{
GameTimer.Stop();
try
{
GameTimer.Tick -= TimerCallback;
} catch {}
}
private void TimerCallback(object sender, object e)
{
StopTimer();
// Other code
}
Thanks in advance,
-justin
Try stopping the timer by using the sender object, not the actual public timer object:
private void TimerCallback(object sender, object e) {
(sender as DispatcherTimer).Stop();
// Other code
}
As a workaround, you could do something like:
// in your class
private bool _allowExecution = false;
Then whenever you start the time set _allowExecution = true; and when you stop the timer, simply add _allowExecution = false;
The last thing will be to add a simply boolean condition on your timer execute: if (_allowExecute) //do your stuff here
Because you initialize a new DispatcherTimer everytime call SetTimer(int interval). You must stop the old DispatcherTimer instance before initialize a new one.
internal void SetTimer(int interval)
{
StopTimer();
GameTimer = new DispatcherTimer();
GameTimer.Tick += TimerCallback;
GameTimer.Interval = new TimeSpan(0,0,0,0,interval);
GameTimer.Start();
}
internal void StopTimer()
{
if(GameTimer != null)
{
GameTimer.Stop();
GameTimer.Tick -= TimerCallback;
GameTimer = null;
}
}
I have a question about System.Windows.Forms.Timer. Is it possible to get Tick event after disposing it? For example, if the message is in the message loop and I dispose the timer meanwhile. If it is possible what is the best way to prevent against it. Do you now any good sources explaining it, because I couldn't find anything explaining it. Here is same code explaining my problem:
namespace TestTimer
{
public partial class Form1 : Form
{
ObjectWithTimer obj = null;
public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
if(obj != null)
{
obj.Deinit();
obj = null;
}
obj = new ObjectWithTimer();
}
}
public class ObjectWithTimer
{
public Object o = new object();
public Timer timer = new Timer();
bool disposed = false;
public ObjectWithTimer()
{
timer.Interval = 10;
timer.Tick += new EventHandler(timer_Tick);
timer.Enabled = true;
}
public void Deinit()
{
timer.Enabled = false;
timer.Tick -= new EventHandler(timer_Tick);
timer.Dispose();
timer = null;
disposed = true;
}
private void timer_Tick(object sender, EventArgs e)
{
if (disposed)
{
//Is it possible to get here
if (timer.Enabled) return;
}
//doing something
}
}
}
Understanding how timers work can help you feel better about it. They are implemented by the operating system, the underlying winapi call to start a timer is SetTimer(). The OS then posts a notification whenever the timer ticks, you get a WM_TIMER message. The plumbing in Winforms ensures that your Tick event handler runs when this message is received.
These messages are stored in the message queue, an internal data structure associated with a window. This queue serializes messages, it is the basic mechanism that ensures that you for example can never lose a mouse click or a keyboard key press, even when the window is unresponsive because the UI thread is busy with something else.
This queue gives reason to be cautious, what happens when the queue stores a WM_TIMER message when you disposed the timer? Unless something drastic is done, you'd still get that message and your Tick event handler will fire.
But no need to worry, WM_TIMER belongs to a small group of messages that are generated in a special way. They are synthesized messages, it is only ever generated when your program asks for a message with GetMessage(). Other common messages that belong that group are WM_PAINT, it fires the Paint event. Note how you can call Invalidate() as often as you like, you still get only a single Paint event. WM_MOUSEMOVE is another one, it fires the MouseMove event. Something you can reason about, no matter how fast you move the mouse, you can never flood the message queue with mouse-move messages.
Another characteristic of these synthesized messages is that they appear to have a "low priority". Given is that they are only ever synthesized when the message queue is empty. Which is why keyboard messages and mouse clicks always generate an event ahead of a paint.
Long story short, you can only get a WM_TIMER message if you ask for a message and the timer is still alive. The Timer.Dispose() method calls KillTimer() under the hood. Which ends any opportunity to still get a Tick event. Only possible way that could get screwed up is when you call the Stop() or Dispose() methods from a worker thread. Don't do that.
The Windows Forms Timer is single threaded so is not possible that while disposing it you are in timer_Tick.
Also you are not detaching your event in deinit function.
This is very easy to test. I've modified your code a bit:
public class Form1 : Form
{
public Form1()
{
var button = new Button();
button.Click += button1_Click;
Controls.Add(button);
}
private void button1_Click(object sender, EventArgs e)
{
var obj = new ObjectWithTimer();
Thread.Sleep(2000);
obj.Deinit();
}
}
public class ObjectWithTimer
{
public System.Windows.Forms.Timer timer = new System.Windows.Forms.Timer();
bool disposed = false;
public ObjectWithTimer()
{
timer.Interval = 100;
timer.Tick += new EventHandler(timer_Tick);
timer.Enabled = true;
}
public void Deinit()
{
timer.Enabled = false;
timer.Tick -= new EventHandler(timer_Tick);
timer.Dispose();
timer = null;
disposed = true;
}
private void timer_Tick(object sender, EventArgs e)
{
"Ticked".Dump();
}
}
The Thread.Sleep ensures the UI thread is occupied while the timer does its ticking.
The result? No, the Tick will not fire after the timer is disabled. Even the timer.Tick -= new EventHandler(timer_Tick); is unnecessary.
I have a issue that I really dont know why it occurs at all. I wpf c# application that use a timer to start a backgroundworker, sometimes the backgroundworker start the task twice, and I don't know why. The code I use is this....
private void startScheduledTask()
{
// Timer settings and start
dpTimer.Interval = TimeSpan.FromMilliseconds(CalculateTimerInterval(CHECK_INTERVAL));
dpTimer.Tick += new EventHandler(StartScheduledActivity);
dpTimer.Start();
}
private void StartScheduledActivity(Object sender, EventArgs args)
{
// Timer tick has occured, start scheduled work
StartScheduledWork();
dpTimer.Interval = TimeSpan.FromMilliseconds(CalculateTimerInterval(CHECK_INTERVAL));
}
private void StartScheduledWork()
{
MyHeavyWorker = new System.ComponentModel.BackgroundWorker();
if ((!MyHeavyWorker.IsBusy) && (MyHeavyWorker != null))
{
MyHeavyWorker.WorkerReportsProgress = true;
MyHeavyWorker.WorkerSupportsCancellation = true;
MyHeavyWorker.ProgressChanged += MyHeavyWorker_ProgressChanged;
MyHeavyWorker.DoWork += MyHeavyWorker_DoWork;
MyHeavyWorker.RunWorkerCompleted += MyHeavyWorker_RunWorkerCompleted;
MyHeavyWorker.RunWorkerAsync();
}
}
private void MyHeavyWorker_DoWork(object sender, System.ComponentModel.DoWorkEventArgs e)
{
// This method sometime run twice at a time
FetchSomeFiles();
}
public int CalculateTimerInterval(int minute)
{
if (minute <= 0)
{
minute = 60;
}
DateTime CurrTime = DateTime.Now;
DateTime now = DateTime.Now;
DateTime future = now.AddMinutes((minute - (now.Minute % minute))).AddSeconds(now.Second * -1).AddMilliseconds(now.Millisecond * -1);
TimeSpan interval = future - now;
NextExecutionTime = future.ToShortTimeString();
NextExecutionDateTime = NextExecutionTime.ToString();
return Convert.ToInt32(interval.TotalMilliseconds);
}
Can anyone see why the method FetchSomeFiles sometimes runs twice at the same time?
It's quite simply because you are each time initializing a new instance of your backgroundworker - so if your timer event occurs before the previous backgroundworker is done it will start a second time with another bg Worker instance. Keep your Backgroundworker reference on class level and initialize it only once.
Do the same thing with the eventhandlers you are adding - move them to the class constructor or to a method called once when your object is instanciated.
//Put this line on class level and only initialize it once.
MyHeavyWorker = new System.ComponentModel.BackgroundWorker();
//Call this once to initialize your Backgroundworker
public void InitializeBackgroundWorker()
{
MyHeavyWorker.WorkerReportsProgress = true;
MyHeavyWorker.WorkerSupportsCancellation = true;
MyHeavyWorker.ProgressChanged += MyHeavyWorker_ProgressChanged;
MyHeavyWorker.DoWork += MyHeavyWorker_DoWork;
MyHeavyWorker.RunWorkerCompleted += MyHeavyWorker_RunWorkerCompleted;
}
Then check for the MyHeavyWorker.IsBusy of your one and only instance to check if it is currently doing some work before deciding to call RunWorkerAsync().
Another method would also be to just stop your timer with dpTimer.Stop() in StartScheduledActivity before you launch your BackgroundWorker and call dpTimer.Start() again in MyHeavyWorker_RunWorkerCompleted. Of course you will have to reconsider how you would like to calculate your next interval since with this solution the countdown does start after your backgroundworker is done - which could be considerably later than the point of the start.
Check
if MyHeavyWorker.IsBusy
before starting the task inside the DoWork() Method. This method will check if DoWork() is still running and will not start another call of this method until it is finished
This is a fictional example but I was wandering what happens if the InitialiseTimer function gets called twice. Does the timer elapsed function get triggered twice. Will this change if the functions are made static?
private static void InitialiseTimer()
{
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 400;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
}
public void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
}
I was going to use below to prevent this
Has an event handler already been added?
Thanks,
Richard
If you register the event handler twice, it will be invoked twice every time the event is raised.
This won't change if you make TheTimer_Elapsed static, because you'll still hold two references to this static method.
In most cases there's no need to write compicated things like what Blair Conrad posted in the question you linked to. Just don't forget to use -= every time you have += and you'll be safe.
I think the following demonstrates the scenario and does indeed fire twice, also propose a simple change (commented code) to the Init method that should fix the behavior. (Not thread safe btw, additional locks would be required)
[TestClass]
public class UnitTest1
{
[TestMethod]
public void TestMethod1()
{
var counter = 0;
var ts = new ThreadStart(() =>
{
Foo.Fired += (o, e) =>
{
counter++;
};
Foo.InitialiseTimer();
Foo.InitialiseTimer();
});
var t = new Thread(ts);
t.Start();
Thread.Sleep(30);
Assert.AreEqual(1, counter);
}
}
public class Foo
{
private static System.Timers.Timer TheTimer = null;
public static event EventHandler Fired;
public static void InitialiseTimer()
{
//if (TheTimer != null)
//{
// TheTimer.Stop();
// TheTimer = null;
//}
TheTimer = new System.Timers.Timer();
TheTimer.Interval = 10;
TheTimer.Elapsed += new ElapsedEventHandler(TheTimer_Elapsed);
TheTimer.AutoReset = false;
TheTimer.Start();
}
public static void TheTimer_Elapsed(object sender, ElapsedEventArgs e)
{
//Do stuff in here
if (Fired != null)
{
Fired(null, null);
}
}
}
if you call the method InitialiseTimer twice you will create two Timers each of them will have only one event handler attached but they might elapse both. It's not really about having the method static or not, it's more about the method itself, you could check if TheTimer is null and do the rest only if it's null so you assign it only once.
If event is registered twice you will have two executions.
You can check if event is null, and the problem will be solved.
Static or not, you are recreating the Timer. So you can invoke the InitialiseTimer many, many times without adding more than a single handler. You will end up with many timers though...