I have created the following extension method to wait for a page to load when using the WebBrowser control.
public static Task<bool> WaitLoad(this WebBrowser webBrowser, int wait)
{
var timerInternalWait = new Timer {Interval = 1000, Tag = "Internal"};
var timerMaxWait = new Timer {Interval = wait};
var tcs = new TaskCompletionSource<bool>();
WebBrowserNavigatingEventHandler navigatingHandler = (sender, args) => timerInternalWait.Stop();
webBrowser.Navigating += navigatingHandler;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler = (sender, args) => { timerInternalWait.Stop(); timerInternalWait.Start(); };
webBrowser.DocumentCompleted += documentCompletedHandler;
EventHandler timerHandler = null;
timerHandler = (sender, args) =>
{
webBrowser.Navigating -= navigatingHandler;
webBrowser.DocumentCompleted -= documentCompletedHandler;
timerInternalWait.Tick -= timerHandler;
timerMaxWait.Tick -= timerHandler;
timerMaxWait.Stop();
timerInternalWait.Stop();
tcs.SetResult(((Timer) sender).Tag.ToString() == "Internal");
};
timerInternalWait.Tick += timerHandler;
timerMaxWait.Tick += timerHandler;
return tcs.Task;
}
I have a couple of question around it though:
When, if ever, do the timers cease to exist and get GCed? I suppose the same question applies for the lambda expressions.
And if currently the answer is never, is there something I can do to ensure that they are cleaned up when no longer needed?
Lastly, ReSharper gives me an implicitly captured closure on the navigatingHandler and the documentCompletedHandler definitions. How can I prevent this from happening?
Really tricky question.
Your timer won't be garbage collected until the task you returned has finished.
Why? ok, here is the tricky part. That's because of the closure ReSharper is telling you about!
All the variables used inside the lambda are kept alive by the framework with a reference to ensure they exist when the lambda is executed and to restore them for it's use. Because you are using the timer inside the lambda the timer will be kept alive while the lambda exists, and the lambda will exists at least until the last line of the lambda has been executed, setting the result of the task.
So it's sure to assume the timer will be kept alive until the lambda has been executed.
Related
So I am making a Robbery system the timer works perfectly on the first start the sequence by the timer goes down is 10,9,8,7...... But on the 2nd try the sequence is 10,8,6,4...... on the 3rd try its 10,7,4,1..... Etc meaning on each start the timer sequence increase the decrease time? How is it possible? Can you make an edit on the code for me?
public int time;
Timer cd = new Timer(2000);
public void robberyCountdown(User player)
{
time = 10;
cd.Elapsed += (source, e) => OnTimer(player);
cd.Start();
}
public void OnTimer(User player)
{
cd.Stop();
cd.Elapsed -= (source, e) => OnTimer(player);
}
but when i use (cd1.Elapsed += (Object source, ElapsedEventArgs e, User player) on OnTimer it gives me an error on the cd.Elapsed -= (source, e) => OnTimer(source, e, player); Line stating local variable is source cannot be used here as it is defined in this scope
I suspect this is because your elapsed event handler isn't actually being removed, so it is firing multiple times at each tick.
The following question/answer discusses how to remove a delegate, and how Delegate.Equals determines which delegate gets removed (if any): C# removing an event handler
However, you are not removing the same handler, you are creating two separate lambda functions that perform exactly the same task within different contexts. .NET isn't very good at collapsing duplicate code - it cannot resolve that your second lambda is the same as your first because they are each created in a different scope, and therefore each has a different closure (the saved image of all visible variables within the scope where it is created).
If you create an actual non-lambda method, and then use delegates rather than lambdas, this problem should go away. Or, you may be able to assign the lambda to a variable that is accessible to both functions (without modifying it in between).
This is a example implementation of Matt Jordan's solution "assign the lambda to a variable that is accessible to both functions"
public int time;
Timer cd = new Timer(2000);
public void robberyCountdown(User player)
{
time = 10;
ElapsedEventHandler handler = null;
handler = (source, e) => OnTimer(player, handler);
cd.Elapsed += handler;
cd.Start();
}
public void OnTimer(User player, ElapsedEventHandler handler)
{
cd.Stop();
cd.Elapsed -= handler;
}
Because lambadas capture variables, not values, handler can reference itself so long as it is already been initialized to a value (null in this example) before you try to use it.
I'm just starting in C# and this is my first question so apologies if this is dumb or the wrong way to ask..
I have a list of timers:
private List<MyTimerClass> MyTimerClassList = new List<MyTimerClass>();
where MyTimerClass just contains a value to keep track of the ID of this timer and a method to initialize it:
timer = new System.Timers.Timer();
and I'm setting up these timers in a standard way with an ElapsedEventHandler:
foreach (var p in AnotherList)
{
var t = new MyTimerClass();
t.init_timer();
t.id = MyOtherClass.ID;
t.timer.Interval = p.Interval;
t.timer.Elapsed += new ElapsedEventHandler((source, e) => RunMyTimerEvent(source, e, p));
t.timer.Enabled = true;
MyTimerClassList.Add(t);
};
These timers are meant to keep running indefinitely and the event handlers run some asynchronous web stuff. Sometimes, the program may get some info that requires it to reschedule, add or remove any or all of these timers, so I have another timer event that regularly checks an update schedule and re configures any of the above timers if needed:
// first check to see see if a timer should be removed
foreach (var t in MyTimerClassList)
{
if (!(UpdatedListofTimers.Exists(p => p.ID == t.id)))
{
t.timer.Stop();
t.timer.Dispose();
}
}
// then check to see if any of the timer intervals has been changed
foreach (var t in UpdatedAnotherList)
{
var item = MyTimerClassList.Find(p => p.id == MyTimerClass.ID);
if (item != null)
{
if (item.timer.Interval != (t.interval * 1000))
{
item.timer.Stop();
item.timer.Interval = (t.Interval * 1000);
item.timer.Start();
}
}
// leaves us with adding a new timer
else {
var n = new MyTimerClass();
n.init_timer();
n.id = t.ID;
n.timer.Interval = t.interval * 1000;
n.timer.Elapsed += new ElapsedEventHandler((sender, ev) => RunMyTimerEvent(sender, ev, t));
n.timer.Enabled = true;
MyTimerClassList.Add(n);
}
};
The code works; it works fine, timers are updated and rescheduled and reconfigured as they should be, they fire off the events and do their stuff. The timer handler event is basically a call to a method that starts off a task:
public void RunMyTimerEvent(object source, ElapsedEventArgs e, AnotherList x)
{
Task<int> t = Task.Run(() => AsyncProcessClass.SomeAsyncStuff(x));
t.Wait();
t.Dispose();
}
The problem is that there is huge memory leak, memory use ramps up very quickly and doesn't get garbage collected even with a hard call to GC.Collect. Inside the async process that I'm calling, there aren't any memory leaks or handlers that aren't disposed of (and I'm aware that you don't necessarily have to dispose of stuff, the garbage collector is smart enough to know whats no longer referenced).
If, instead of reconfiguring the timers when I get an update, I delete them all and recreate them from scratch, the memory leak goes away. Am I doing something completely wrong here ? Instead of changing the timer interval on the fly as it were, do you have to delete it and create a new one ? Can another timer event not reconfigure a different timer ? Is it the weak reference problem with the method inside the event handler, that it never gets marked for garbage collection ? I don't understand weak references that well, at least not enough to have tried it. Maybe I'm doing something that's obviously wrong ?
I have a project here and it has set by default that the actions occur by MouseEnter event. I mean, opening a Window, closing, returning, whatever, happens only by the MouseEnter event.
I was requested to make the event fire only after 3 seconds. That means that the user will place the mouse on the control and only after 3 seconds the event must happen for all the controls in the window.
So, I thought about a global timer or something alike, that will return false untill the timer reaches 3... I think that's the way...
Geez, does anybody knows how can I make such thing?
Thanks!!
You can define a class that will expose a DelayedExecute method that receives an action to execute and creates timers as needed for the delayed execution. It would look something like this:
public static class DelayedExecutionService
{
// We keep a static list of timers because if we only declare the timers
// in the scope of the method, they might be garbage collected prematurely.
private static IList<DispatcherTimer> timers = new List<DispatcherTimer>();
public static void DelayedExecute(Action action, int delay = 3)
{
var dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
// Add the timer to the list to avoid it being garbage collected
// after we exit the scope of the method.
timers.Add(dispatcherTimer);
EventHandler handler = null;
handler = (sender, e) =>
{
// Stop the timer so it won't keep executing every X seconds
// and also avoid keeping the handler in memory.
dispatcherTimer.Tick -= handler;
dispatcherTimer.Stop();
// The timer is no longer used and shouldn't be kept in memory.
timers.Remove(dispatcherTimer);
// Perform the action.
action();
};
dispatcherTimer.Tick += handler;
dispatcherTimer.Interval = TimeSpan.FromSeconds(delay);
dispatcherTimer.Start();
}
}
Then you can call it like this:
DelayedExecutionService.DelayedExecute(() => MessageBox.Show("Hello!"));
or
DelayedExecutionService.DelayedExecute(() =>
{
DoSomething();
DoSomethingElse();
});
I just wanted to add a simpler solution:
public static void DelayedExecute(Action action, int delay = 3000)
{
Task.Factory.StartNew(() =>
{
Thread.Sleep(delay);
action();
}
}
Then use it just like in this other answer
Lets say I have a button that gets clicked and it does this:
public void ButtonClick(object sender, EventArgs e)
{
System.Timers.Timer NewTimer = new System.Timers.Timer();
NewTimer.AutoReset = false;
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
public void TimerElapsed(object sender, ElapsedEventArgs e)
{
}
If this button gets clicked 100 times what happens to those instances that have been created? Will garbage collection kick in or does the System.Timers.Timer.Close method need calling and if it does where do you call it from?
No this will not cause a memory leak. In fact the way your code is written it's not guaranteed to execute properly. Timers.Timer is really just a wrapper over Threading.Timer and it's explicitly listed as being collectable even if it's currently running.
http://msdn.microsoft.com/en-us/library/system.threading.timer.aspx
Here you keep no reference to it and hence the very next GC could collect it while your form is still running and before the event ever fires
EDIT
The documentation for Timers.Timer appears to be incorrect. The Timer instance will not be collected if it's unreferenced. It will indeed live on
var timer = new System.Timers.Timer
{
Interval = 400,
AutoReset = true
};
timer.Elapsed += (_, __) => Console.WriteLine("Stayin alive (2)...");
timer.Enabled = true;
WeakReference weakTimer = new WeakReference(timer);
timer = null;
for (int i = 0; i < 100; i++)
{
GC.Collect();
GC.WaitForPendingFinalizers();
}
Console.WriteLine("Weak Reference: {0}", weakTimer.Target);
Console.ReadKey();
They will be collected once method is left. TimerElapsed will be either called or not depending on when Timer gets finalized. Most likely it will be dead long before 1 second passed.
When you call Timer.Close() you thus call Timer.Dispose() that de-registers timer from timer queue and in that case TimerElapsed won't be called (of course if it was not called before).
If you leave timer not closed, GC will eventaully call Finalize() that in turn will call Dispose(). But there is not exact knowledge when it will happen :)
See below example, Console.Out.WriteLine("called!!!") will never execute:
using (System.Timers.Timer NewTimer = new System.Timers.Timer())
{
NewTimer.AutoReset = false;
ElapsedEventHandler TimerElapsed = (sender, args) => { Console.Out.WriteLine("called!!!"); };
NewTimer.Elapsed += new ElapsedEventHandler(TimerElapsed);
NewTimer.Interval = 1000;
NewTimer.Start();
}
Thread.Sleep(3000);
After answers by the_joric and JaredPar and running profiler tests which showed timers sticking around after garbage collection kicked in the reason they stuck around was because there is a reference to the event handler sticking around. For a more detailed explanation see this answer.
The real answer is that it is a memory leak unless the timer is closed in the elapsed event handler.
Just goes to show that although I trust the answers on SO (maybe too much) from the great contributors they may be slightly off.
I have the following code:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
this.FoundStep += delegate(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.Start();
return retval;
}
Notice how I register my event member (FoundStep) to local in-place anonymous function.
My question is: when the function 'FindStepByType' will end - will the anonymous function be removed automatically from the delegate list of the event or I have to manually remove it before steping out the function? (and how do I do that?)
I hope my question was clear.
Your code has a few problems (some you and others have identified):
The anonymous delegate cannot be removed from the event as coded.
The anonymous delegate will live longer than the life of the method calling it because you've added it to FoundStep which is a member of this.
Every entry into FindStepsByType adds another anonymous delegate to FoundStep.
The anonymous delegate is a closure and effectively extends the lifetime of retval, so even if you stop referencing retval elsewhere in your code, it's still held by the anonymous delegate.
To fix this, and still use an anonymous delegate, assign it to a local variable, and then remove the handler inside a finally block (necessary in case the handler throws an exception):
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
List<IWFResourceInstance> retval = new List<IWFResourceInstance>();
EventHandler<WalkerStepEventArgs> handler = (sender, e) =>
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
};
this.FoundStep += handler;
try
{
this.Start();
}
finally
{
this.FoundStep -= handler;
}
return retval;
}
With C# 7.0+ you can replace the anonymous delegate with a local function, achieving the same effect:
public List<IWFResourceInstance> FindStepsByType(IWFResource res)
{
var retval = new List<IWFResourceInstance>();
void Handler(object sender, WalkerStepEventArgs e)
{
if (e.Step.ResourceType == res) retval.Add(e.Step);
}
FoundStep += Handler;
try
{
this.Start();
}
finally
{
FoundStep -= Handler;
}
return retval;
}
Below is approach about how unsubscribe event in anonymous method:
DispatcherTimer _timer = new DispatcherTimer();
_timer.Interval = TimeSpan.FromMilliseconds(1000);
EventHandler handler = null;
int i = 0;
_timer.Tick += handler = new EventHandler(delegate(object s, EventArgs ev)
{
i++;
if(i==10)
_timer.Tick -= handler;
});
_timer.Start();
No, it will not be removed automatically. In this sense, there's not a difference between an anonymous method and a "normal" method. If you want, you should manually unsubscribe from the event.
Actually, it'll capture other variables (e.g. res in your example) and keep them alive (prevents garbage collector from collecting them) too.
When using an anonymous delegate (or a lambda expression) to subscribe to an event does not allow you to easily unsubscribe from that event later. An event handler is never automatically unsubscribed.
If you look at your code, even though you declare and subscribe to the event in a function, the event you are subscribing to is on the class, so once subscribed it will always be subscribed even after the function exits. The other important thing to realize is that each time this function is called, it will subscribe to the event again. This is perfectly legal since events are essentially multicast delegates and allow multiple subscribers. (This may or may not be what you intend.)
In order to unsubscribe from the delegate before you exit the function, you would need to store the anonymous delegate in a delegate variable and add the delegate to the event. You should then be able to remove the delegate from the event before the function exits.
For these reasons, if you will have to unsubscribe from the event at some later point it is not recommended to use anonymous delegates. See How to: Subscribe to and Unsubscribe from Events (C# Programming Guide) (specifically the section titled "To subscribe to events by using an anonymous method").