Consider the following code:
public class Bar {
Foo foo;
void Go() {
foo = new Foo();
foo.Send(...);
foo.Dispose();
foo = null;
}
}
public class Foo : IDisposable {
public void Send(byte[] bytes) {
SocketAsyncEventArgs args = new SocketAsyncEventArgs();
args.SetBuffer(bytes, 0, bytes.Length);
args.UserToken = socket;
args.RemoteEndPoint = endPoint;
args.Completed += new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);
socket.SendAsync(args);
}
private void OnSendCompleted(object sender, SocketAsyncEventArgs e) {
Debug.WriteLine("great");
}
public void Dispose() {
//
}
}
So class Bar runs the Init method which instantiates the Foo class and fires off the Send method, then destroys the Foo instance. The Send method meanwhile instantiates a method level SocketAsyncEventArgs, sets up a Completed event and then fires off the SendAsync method.
Assuming that the SendAsync completes after the Foo instance has been set to null, what happens to the event handler? Does it still fire? If I don't want it to fire, how do I properly clean up the Foo class, knowing that a method level variable spawned off an event.
Yes, it will still fire. Setting a variable to null doesn't trigger garbage collection or anything like that. It just sets the variable to null. (It's important to differentiate between a variable and an instance. There's no such concept as "setting an instance to null". If I write my home address down on a piece of paper, then rub it out again, that doesn't destroy my house.)
It sounds like you may want your Dispose method to "remember" that the object has been cleaned up, and then if OnSendCompleted is called after disposal, just ignore it. Alternatively, keep track of any "requests in flight" and cancel them in in Dispose... noting that some requests might complete while you're cancelling the whole lot.
Another point to note: instead of explicitly calling Dispose(), you should almost always use a using statement, which will make sure that Dispose() is called however the using statement ends (e.g. with an exception).
What about trying to unhook the event by using -= in your OnSendCompleted method ?
e.Completed -= new EventHandler<SocketAsyncEventArgs>(OnSendCompleted);
Related
I have a class with EventHandler bindings at the constructor, that will be instantiated thousand times within application lifecycle. The question is: Will this approach leads to memory/thread leaks?
I did this way (code below), because I need to be notified every time SomeMethod() runs, whatever instance run it. Foo class (the publisher) will be short-lived, however the handlers will live until the application closes.
I ask this because, when working with Windows Forms, each form can hold several event handlers/delegates and everything is fine because all those delegates are inside the form and will be disposed when the form closes. But how about static event handlers/delegates, that could be even on separate projects?
Will I need to write a destructor to detach those event handlers?
Should I go with Weak Event Pattern?
Restriction: I must do this with .NET 3.5. I know I could do this with TPL, setting a "Fire and Forget" Task.
Thank you in advance.
Code:
public class Foo
{
public event EventHandler SomeEvent;
public Foo()
{
SomeEvent += FooHandlers.Foo_SomeEvent1;
SomeEvent += FooHandlers.Foo_SomeEvent2;
}
public void RaiseEvents(EventHandler evt, EventArgs args)
{
var eventObj = evt;
var listeners = eventObj.GetInvocationList();
foreach (var listener in listeners)
{
var method = (EventHandler)listener;
ThreadPool.QueueUserWorkItem(callBack => method(this, args));
// Handlers will do a lot of things, so I don't want
// them blocking the Main thread
}
}
public void SomeMethod()
{
// do something here
RaiseEvents(SomeEvent, new EventArgs());
}
}
public static class FooHandlers
{
public static void Foo_SomeEvent1(object sender, EventArgs e)
{
//do something here
}
public static void Foo_SomeEvent2(object sender, EventArgs e)
{
//do something different here
}
}
Since your handlers are static methods the delegate you're adding to the event doesn't have an object instance, so there is no object instance being kept alive for the duration of the object with the event.
And even if you did use an object instance to attach the handler, it wouldn't be a problem, because the object with the event is short lived. The only time there is a problem is when the object with the event is long lived, and the object that has a handler to itself assigned is short lived, and consumes a lot of resources to keep alive.
I have a callback that is called from a 3rd party com interop, and it's called quite often. (Thousands of times.) I raise an event in one the callback's methods and I was curious if it would be better to use a class member for the event args or create a new instance of the event args class for each event? The event I raise updates the UI.
I am wondering if there is a point in creating another instance for each event when it's going to be called a lot.
Using a class member:
private ProgressEventArgs m_eventArgs;
public bool ProgressStep(ProgressType eType, string bsMessage, int lProgressPos)
{
if (ProgressEventStep != null)
{
m_eventArgs.Value = lProgressPos;
ProgressEventStep(this, m_eventArgs);
}
return true;
}
Or
public bool ProgressStep(ProgressType eType, string bsMessage, int lProgressPos)
{
if (ProgressEventStep != null)
ProgressEventStep(this, new ProgressEventArgs(lProgressPos));
return true;
}
Which would be preferred? Or does it much matter?
Assuming the constructor for ProgressEventStep doesn't do anything unusual there should be very little overhead in creating objects.
Performance aside, since you're reusing the same object in the first scenario you risk getting the wrong event data in a multi-threaded scenario.
In the constructor of an object, Listener, we take an argument and subscribe to one of its events. If an exception is thrown within the constructor after the event is subscribed the OnSomethingChanged() method is still called when the event is raised - even through the object was not successfully constructed and, as far as I'm aware, no instance exists.
Now I can fix this by obviously re-factoring the design slightly, however I'm more interested in why an instance method is called even though the constructor did not complete successfully? If the method uses any local variables that have not been initialised before the exception then obviously it goes BOOM!
class Program
{
static void Main(string[] args)
{
Input input = new Input();
try
{
new Listener(input);
}
catch (InvalidOperationException)
{
// swallow
}
input.ChangeSomething(); // prints "Something changed!"
}
}
public class Listener
{
public Listener(Input input)
{
input.SomethingChanged += OnSomethingChanged; // subscibe
throw new InvalidOperationException(); // do not let constructor succeed
}
void OnSomethingChanged(object sender, EventArgs e)
{
Console.WriteLine("Something changed!");
}
}
public class Input
{
public event EventHandler SomethingChanged;
public void ChangeSomething()
{
SomethingChanged(this, EventArgs.Empty);
}
}
While throwing an exception from a constructor means an instance may potentially end up in an incomplete state, doing so doesn't stop the instance itself from being created and stored in memory (as that happens before its constructor is called).
Furthermore, the event handler has already been bound by the time you throw the exception, so raising the event will cause the handler to be invoked.
To quickly illustrate the first point, if you gave Listener a field to initialize in its constructor, then tried to initialize it after throwing the exception (which obviously isn't going to work):
string foo;
public Listener(Input input, string f)
{
input.SomethingChanged += OnSomethingChanged;
// Because this is thrown...
throw new InvalidOperationException();
// ... this never happens
foo = f;
}
And then tried to access it in its OnSomethingChanged handler:
void OnSomethingChanged(object sender, EventArgs e)
{
Console.WriteLine("Listener.foo = " + foo);
}
Regardless of how you call new Listener(...), the output would be
Listener.foo =
simply because the listener didn't get a chance to initialize its foo field. Although it wasn't fully initialized, it's still a complete object in terms of allocation.
Let's say we have the following setup:
public class ClassA
{
public event EventHandler SomeEvent;
}
public class ClassB : IDisposable
{
public void SomeMethod(ClassA value)
{
value.SomeEvent += (s, e) => { DoSomething(); };
}
void DoSomething() { }
void Dispose() { }
}
public static class Program
{
static void Main()
{
var a = new ClassA();
using (var b = new ClassB())
b.SomeMethod(a);
// POINT OF QUESTION!!
}
}
What happens when the event SomeEvent is raised after the "POINT OF QUESTION"?
It will call method of disposed object. That's why it is important to unsubscribe. It even can lead to memory leaks.
You should use the Dispose() method of ClassB to unsubscribe from the ClassA event. You run the risk of classes not being garbage collected which of course leads to potential memory leaks. You should always unsub from events.
Nothing you have above would unhook your event handler. Since both a and b go out of scope at the same time, you'd be safe. Since a and b can both be collected, then a will not keep b alive.
If you were to raise the ClassA.SomeEvent event after your using statement, then ClassB.DoSomething will be called even though b has been disposed. You would have to explicitly remove the event handler in this case.
If you were to retain a reference to a somewhere else, then b would be keep alive by a. Again, because the event handler has not been removed.
Nothing. Runtime doesn't know about Dispose method and call to this method inside using statement do nothing to memory management.
Garbage collection is all about memory management, but IDisposable (and Finalizer) is about resource management, so you still should think yourself and implement it manually (and propertly, for example unsubscribe in Dispose).
A simple question on callbacks. Do callback functions return to the next line in the calling function after completion ?
class A
{
public delegate void A();
public event A onA;
public void func()
{
//some code 1
onA();
//some code 2
}
So the question is will onA event go and execute the respective handler and then come back to 'some code 2' bit or is this asynchronous and code will not wait for the event to be fully handled?
I hope the question is clear.
Thanks
}
The way you used delegate: is synchronous. If you want asynchronous you must invoke delegate with: BeginInvoke method.
Yes, in your example onA() will trigger all over the event handlers hooked up to A to fire. They are just methods that will be called. After they are all called, control will return to func().
It is not asynchronous - you are only using one thread. Everything will happen in a well defined order.
A good way to experiment would be to step through the code in your example using the built in debugger.
Your code isn't assync. But you can Use Delegates Asynchronously.
No, calling a event isn't a assync thing. Your code func() will only continue after onA() ends running.
You would use BeginInvoke or Threading if will wants assync code running.
Read more about delegate invokes here.
As others have pointed out, this is entirely synchronous. If you wanted to execute this asynchronously you would have to write this differently.
Additionally, if the event 'onA' is not subscribed to, onA() will raise a null reference exception.
The usual pattern is to define an event 'Foo' and a method 'OnFoo' which you call when the event occurs. From the name of the event I suspect this is what you desire - e.g.:-
class Foo // Class and member names must be distinct
{
public delegate void ADelegate();
public event ADelegate A;
private void OnA()
{
if(A != null)
A();
}
public void Func()
{
// Some code...
OnA();
// More code...
}
}
If you want to call the subscribed event handlers asynchronously you can use BeginInvoke() and EndInvoke() thus:-
class Foo // Class and member names must be distinct
{
public delegate void ADelegate();
public event ADelegate A;
private void OnA()
{
if (A == null) return;
// There may be multiple subscribers, invoke each separately.
foreach(ADelegate del in A.GetInvocationList())
del.BeginInvoke(SubscriberCallback, del);
}
private void SubscriberCallback(IAsyncResult result)
{
var del = (ADelegate) result.AsyncState;
del.EndInvoke(result);
// Do something in the callback...
}
public void Func()
{
// Some code...
OnA();
// More code...
}
}
Note that this code won't wait to finish executing the event subscriber(s), you would have to thread the async result through the event call to ensure this happens.
Note that the 'callback' is the method you specify in the asynchronous BeginInvoke (since it is 'called back' once the async work is done), and doesn't return to Func() as it is executed in a separate thread.