This question already has answers here:
Checking for null before event dispatching... thread safe?
(6 answers)
Closed 2 years ago.
In order to raise an event we use a method OnEventName like this:
protected virtual void OnSomethingHappened(EventArgs e)
{
EventHandler handler = SomethingHappened;
if (handler != null)
{
handler(this, e);
}
}
But what is the difference with this one ?
protected virtual void OnSomethingHappened(EventArgs e)
{
if (SomethingHappened!= null)
{
SomethingHappened(this, e);
}
}
Apparently the first is thread-safe, but why and how ?
It's not necessary to start a new thread ?
There is a tiny chance that SomethingHappened becomes null after the null check but before the invocation. However, MulticastDelagates are immutable, so if you first assign a variable, null check against the variable and invoke through it, you are safe from that scenario (self plug: I wrote a blog post about this a while ago).
There is a back side of the coin though; if you use the temp variable approach, your code is protected against NullReferenceExceptions, but it could be that the event will invoke event listeners after they have been detached from the event. That is just something to deal with in the most graceful way possible.
In order to get around this I have an extension method that I sometimes use:
public static class EventHandlerExtensions
{
public static void SafeInvoke<T>(this EventHandler<T> evt, object sender, T e) where T : EventArgs
{
if (evt != null)
{
evt(sender, e);
}
}
}
Using that method, you can invoke the events like this:
protected void OnSomeEvent(EventArgs e)
{
SomeEvent.SafeInvoke(this, e);
}
Since C# 6.0 you can use monadic Null-conditional operator ?. to check for null and raise events in easy and thread-safe way.
SomethingHappened?.Invoke(this, args);
It’s thread-safe because it evaluates the left-hand side only once, and keeps it in a temporary variable. You can read more here in part titled Null-conditional operators.
Update:
Actually Update 2 for Visual Studio 2015 now contains refactoring to simplify delegate invocations that will end up with exactly this type of notation. You can read about it in this announcement.
I keep this snippet around as a reference for safe multithreaded event access for both setting and firing:
/// <summary>
/// Lock for SomeEvent delegate access.
/// </summary>
private readonly object someEventLock = new object();
/// <summary>
/// Delegate variable backing the SomeEvent event.
/// </summary>
private EventHandler<EventArgs> someEvent;
/// <summary>
/// Description for the event.
/// </summary>
public event EventHandler<EventArgs> SomeEvent
{
add
{
lock (this.someEventLock)
{
this.someEvent += value;
}
}
remove
{
lock (this.someEventLock)
{
this.someEvent -= value;
}
}
}
/// <summary>
/// Raises the OnSomeEvent event.
/// </summary>
public void RaiseEvent()
{
this.OnSomeEvent(EventArgs.Empty);
}
/// <summary>
/// Raises the SomeEvent event.
/// </summary>
/// <param name="e">The event arguments.</param>
protected virtual void OnSomeEvent(EventArgs e)
{
EventHandler<EventArgs> handler;
lock (this.someEventLock)
{
handler = this.someEvent;
}
if (handler != null)
{
handler(this, e);
}
}
For .NET 4.5 it's better to use Volatile.Read to assign a temp variable.
protected virtual void OnSomethingHappened(EventArgs e)
{
EventHandler handler = Volatile.Read(ref SomethingHappened);
if (handler != null)
{
handler(this, e);
}
}
Update:
It's explained in this article: http://msdn.microsoft.com/en-us/magazine/jj883956.aspx. Also, it was explained in Fourth edition of "CLR via C#".
Main idea is that JIT compiler can optimize your code and remove the local temporary variable. So this code:
protected virtual void OnSomethingHappened(EventArgs e)
{
EventHandler handler = SomethingHappened;
if (handler != null)
{
handler(this, e);
}
}
will be compiled into this:
protected virtual void OnSomethingHappened(EventArgs e)
{
if (SomethingHappened != null)
{
SomethingHappened(this, e);
}
}
This happens in certain special circumstances, however it can happen.
It depends on what you mean by thread-safe. If your definition only includes the prevention of the NullReferenceException then the first example is more safe. However, if you go with a more strict definition in which the event handlers must be invoked if they exist then neither is safe. The reason has to do with the complexities of the memory model and barriers. It could be that there are, in fact, event handlers chained to the delegate, but the thread always reads the reference as null. The correct way of fixing both is to create an explicit memory barrier at the point the delegate reference is captured into a local variable. There are several ways of doing this.
Use the lock keyword (or any synchronization mechanism).
Use the volatile keyword on the event variable.
Use Thread.MemoryBarrier.
Despite the awkward scoping problem which prevents you from doing the one-line initializer I still prefer the lock method.
protected virtual void OnSomethingHappened(EventArgs e)
{
EventHandler handler;
lock (this)
{
handler = SomethingHappened;
}
if (handler != null)
{
handler(this, e);
}
}
It is important to note that in this specific case the memory barrier problem is probably moot because it is unlikely that reads of variables will be lifted outside method calls. But, there is no guarentee especially if the compiler decides to inline the method.
Declare your event like this to get thread safety:
public event EventHandler<MyEventArgs> SomethingHappened = delegate{};
And invoke it like this:
protected virtual void OnSomethingHappened(MyEventArgs e)
{
SomethingHappened(this, e);
}
Although the method is not needed anymore..
Update 2021-09-01
Today I would simply do (which do not require the emty delegate):
SomethingHappened?.Invoke(e);
Someone pointed out that using an empty delegate has a larger overhead. That's true. But from an application perspetive, the performance impact is minimal. Therefore, it's much more important to choose the solution that has the cleanest code.
Actually, the first is thread-safe, but the second isn't. The problem with the second is that the SomethingHappened delegate could be changed to null between the null verification and the invocation. For a more complete explanation, see http://blogs.msdn.com/b/ericlippert/archive/2009/04/29/events-and-races.aspx.
Actually, no, the second example isn't considered thread-safe. The SomethingHappened event could evaluate to non-null in the conditional, then be null when invoked. It's a classic race condition.
I tried to pimp out Jesse C. Slicer's answer with:
Ability to sub/unsubscribe from any thread while within a raise (race condition removed)
Operator overloads for += and -= at the class level
Generic caller defined delegates
public class ThreadSafeEventDispatcher<T> where T : class
{
readonly object _lock = new object();
private class RemovableDelegate
{
public readonly T Delegate;
public bool RemovedDuringRaise;
public RemovableDelegate(T #delegate)
{
Delegate = #delegate;
}
};
List<RemovableDelegate> _delegates = new List<RemovableDelegate>();
Int32 _raisers; // indicate whether the event is being raised
// Raises the Event
public void Raise(Func<T, bool> raiser)
{
try
{
List<RemovableDelegate> raisingDelegates;
lock (_lock)
{
raisingDelegates = new List<RemovableDelegate>(_delegates);
_raisers++;
}
foreach (RemovableDelegate d in raisingDelegates)
{
lock (_lock)
if (d.RemovedDuringRaise)
continue;
raiser(d.Delegate); // Could use return value here to stop.
}
}
finally
{
lock (_lock)
_raisers--;
}
}
// Override + so that += works like events.
// Adds are not recognized for any event currently being raised.
//
public static ThreadSafeEventDispatcher<T> operator +(ThreadSafeEventDispatcher<T> tsd, T #delegate)
{
lock (tsd._lock)
if (!tsd._delegates.Any(d => d.Delegate == #delegate))
tsd._delegates.Add(new RemovableDelegate(#delegate));
return tsd;
}
// Override - so that -= works like events.
// Removes are recongized immediately, even for any event current being raised.
//
public static ThreadSafeEventDispatcher<T> operator -(ThreadSafeEventDispatcher<T> tsd, T #delegate)
{
lock (tsd._lock)
{
int index = tsd._delegates
.FindIndex(h => h.Delegate == #delegate);
if (index >= 0)
{
if (tsd._raisers > 0)
tsd._delegates[index].RemovedDuringRaise = true; // let raiser know its gone
tsd._delegates.RemoveAt(index); // okay to remove, raiser has a list copy
}
}
return tsd;
}
}
Usage:
class SomeClass
{
// Define an event including signature
public ThreadSafeEventDispatcher<Func<SomeClass, bool>> OnSomeEvent =
new ThreadSafeEventDispatcher<Func<SomeClass, bool>>();
void SomeMethod()
{
OnSomeEvent += HandleEvent; // subscribe
OnSomeEvent.Raise(e => e(this)); // raise
}
public bool HandleEvent(SomeClass someClass)
{
return true;
}
}
Any major problems with this approach?
The code was only briefly tested and edited a bit on insert.
Pre-acknowledge that List<> not a great choice if many elements.
For either of these to be thread safe, you are assuming that all the objects that subscribe to the event are also thread safe.
Related
I've seen many developers when wanting to invoke an Event they assign it to a local variable named handler and invoke handler instead of invoking Event directly.
Why we are not invoking Events directly?
private void OnSomethingChanged(EventArgs e)
{
if (SomethingEvent != null)
{
SomethingEvent(this, e);
}
}
The code you've posted isn't thread-safe, basically. If the final subscriber unsubscribes in a different thread after the if check but before the invocation, you'll get a NullReferenceException.
One option is to write an extension method:
public static void NullSafeInvoke(this EventHandler handler,
object sender, EventArgs e)
{
if (handler != null)
{
handler(this, e);
}
}
You can then write:
private void OnSomethingChanged(EventArgs e)
{
SomethingEvent.NullSafeInvoke(this, e);
}
You'd probably want another overload for EventHandler<T>, too.
There is a possibility of a race condition if the event is not copied (relevant to multi-threaded applications only).
If one thread unsubscribes from the event just after the null check leaving nothing subscribed to it, you will get a NullReferenceException.
I also don't understand why. There is a simple and pretty safe method:
// when constructing of instance, to create empty subscription
public event EventHandler SomethingEvent = delegate { };
private void OnSomethingChanged(EventArgs e)
{
// and call it directly
SomethingEvent(this, e);
}
I may be misunderstanding something fundamental here as I'm new to these concepts so please bear with me.
I'm currently removing methods from an event like so:
scheduleView.TouchDown -= scheduleView_TouchDown;
And then on other occasions - adding the methods:
scheduleView.TouchDown += scheduleView_TouchDown;
It all works fine so far, and I can understand it's possible to add several methods, like so:
scheduleView.TouchDown += scheduleView_TouchDown;
scheduleView.TouchDown += scheduleView_AnotherTouchDownEventHandler;
But how would I then later check what methods were wired up to this event?
Interestingly, you can't (at least, from the outside). An event is only obliged to offer 2 accessors - add and remove. There are other accessor methods defined in the CLI spec, but they aren't used in C# or anywhere else AFAIK. The key point: we can't ask an event what is subscribed (and indeed, we shouldn't need to know). All you can do is: add or remove.
If you are worried about double-subscribing, then note that if you try to unsubscribe and you haven't actually subscribed, then under every sane implementation this is simply a no-op; which means you can do:
// make sure we are subscribed once but **only** once
scheduleView.TouchDown -= scheduleView_TouchDown;
scheduleView.TouchDown += scheduleView_TouchDown;
From the perspective of the code raising the event, you rarely need to know who - simply:
// note I'm assuming a "field-like event" implementation here; otherwise,
// change this to refer to the backing-field, or the delegate from the
// event-handler-list
var handler = TouchDown;
if(handler != null) handler(this, EventArgs.Empty); // or similar
There is also a way to break the delegate list into individual subscribers, but it is very rarely needed:
var handler = TouchDown;
if(handler != null) {
foreach(EventHandler subscriber in handler.GetInvocationList()) {
subscriber(this, EventArgs.Empty);
}
}
The main uses for this are:
when you want to perform exception-handling on a per-subscriber basis
when the delegate returns a value or changes state, and you need to handle that on a per-subscriber basis
Yes: If you are within the class that publishes the Event, you can just access the delegate, and you can call the GetInvocationList method to get a list of the subscribers.
No: If you are working outside the class, as the delegate is not exposed to you. You could use reflection to get at it, but that would be a hack, at best.
In the type that declares the event, you can use GetInvocationList() to find out which delegates are subscribed:
public class EventProvider
{
public event EventHandler SomeEvent;
protected virtual void OnSomeEvent(EventArgs args)
{
if (SomeEvent != null)
{
var delegates = SomeEvent.GetInvocationList();
foreach (var del in delegates)
{
Console.WriteLine("{0} has subscribed to SomeEvent", del.Method.Name);
}
SomeEvent(this, args);
}
}
public void RaiseSomeEvent()
{
OnSomeEvent(EventArgs.Empty);
}
}
public class Program
{
public static void Main()
{
EventProvider provider = new EventProvider();
provider.SomeEvent += Callback1;
provider.SomeEvent += Callback2;
provider.RaiseSomeEvent();
}
public static void Callback1(object sender, EventArgs e)
{
Console.WriteLine("Callback 1!");
}
public static void Callback2(object sender, EventArgs e)
{
Console.WriteLine("Callback 2!");
}
}
This produces the following output:
Callback1 has subscribed to SomeEvent
Callback2 has subscribed to SomeEvent
Callback 1!
Callback 2!
I would like to hear opinions on below code snippet. Is there anything that can be improved? Is the event handler/raiser naming following best practices? I know it is not that useful to handle and raise events in the same class but this is just a snippet.
public class MyControl
{
public MyControl()
{
this.LogWritten += this.HandleMyControlLogWritten;
}
// Event handler
void HandleMyControlLogWritten(object sender, EventArgs e)
{
}
// Event object
public event Action<object, EventArgs> LogWritten;
// Event raiser
protected virtual void OnLogWritten(EventArgs e)
{
if (this.LogWritten != null)
{
this.LogWritten(this, e);
}
}
}
The main change I'd recommend would be to get a copy of the event handler:
// Event raiser
protected virtual void OnLogWritten(EventArgs e)
{
var handler = this.LogWritten;
if (handler != null)
{
handler(this, e);
}
}
This is important if you're planning to (eventually) use this class in a multi-threaded scenario. As such, I find that it's a good "best practice" to get into the habit of using. The issue is that, when using in multiple threads, without creating the copy, it's possible that the only "handler" attached could unsubscribe between the null check and the invocation, which would cause a runtime error. By copying to a temporary variable (the var handler = this.LogWritten;) line, you're effectively creating a "snapshot" of the subscriber list, and then checking it for null and invoking if required.
The other change is in the event declaration itself. Instead of using Action<T1,T2>:
// Event object
public event Action<object, EventArgs> LogWritten;
I would recommend using EventHandler<TEventArgs> (if you want to use a custom EventArgs subclass) or EventHandler (for standard EventArgs). These are more "standard practice", and will be what other developers expect:
// Event object
public event EventHandler LogWritten;
I have a static class that I would like to raise an event as part of a try catch block within a static method of that class.
For example in this method I would like to raise a custom event in the catch.
public static void saveMyMessage(String message)
{
try
{
//Do Database stuff
}
catch (Exception e)
{
//Raise custom event here
}
}
Thank you.
Important: be very careful about subscribing to a static event from instances. Static-to-static is fine, but a subscription from a static event to an instance handler is a great (read: very dangerous) way to keep that instance alive forever. GC will see the link, and will not collect the instance unless you unsubscribe (or use something like a WeakReference).
The pattern for creating static events is the same as instance events, just with static:
public static event EventHandler SomeEvent;
To make life easier (re null checking), a useful trick here is to add a trivial handler:
public static event EventHandler SomeEvent = delegate {};
Then you can simply invoke it without the null-check:
SomeEvent(null, EventArgs.Empty);
Note that because delegate instances are immutable, and de-referencing is thread-safe, there is never a race condition here, and no need to lock... who-ever is subscribed when we de-reference gets invoked.
(adjust for your own event-args etc).
This trick applies equally to instance events.
Your event would also need to be static:
public class ErrorEventArgs : EventArgs
{
private Exception error;
private string message;
public ErrorEventArgs(Exception ex, string msg)
{
error = ex;
message = msg;
}
public Exception Error
{
get { return error; }
}
public string Message
{
get { return message; }
}
}
public static class Service
{
public static EventHandler<ErrorEventArgs> OnError;
public static void SaveMyMessage(String message)
{
EventHandler<ErrorEventArgs> errorEvent = OnError;
if (errorEvent != null)
{
errorEvent(null, new ErrorEventArgs(null, message));
}
}
}
And Usage:
public class Test
{
public void OnError(object sender, ErrorEventArgs args)
{
Console.WriteLine(args.Message);
}
}
Test t = new Test();
Service.OnError += t.OnError;
Service.SaveMyMessage("Test message");
Several folks have offered up code examples, just don't fire an event using code such as:
if(null != ExampleEvent)
{
ExampleEvent(/* put parameters here, for events: sender, eventArgs */);
}
as this contains a race condition between when you check the event for null and when you actually fire the event. Instead use a simple variation:
MyEvent exampleEventCopy = ExampleEvent;
if(null != exampleEventCopy)
{
exampleEventCopy(/* put parameters here, for events: sender, eventArgs */);
}
This will copy any event subscribers into the exampleEventCopy, which you can then use as a local-only version of the public event without having to worry about any race conditions (Essentially, it is possible that another thread could pre-empt you right after you have checked the public event for null and proceed to remove all subscribers from the event, causing the subsequent firing of the event to throw an exception, by using a local-only copy, you avoid the possibility of another thread removing subscribers, since there is no way they could access the local variable).
Note: VS2008, C#
Just declare an event as you normally would within the static class, but be sure to mark the event as static:
public static event EventHandler Work;
Then just subscribe to it as you normally would.
Just to add "Delegates are immutable" So, as shown in the example above the following line obtains a copy of the delegate.
EventHandler<ErrorEventArgs> errorEvent = OnError;
The way I did this is the following:
1- define a delegate (this will enable you to have customized arguments):
public delegate void CustomeEventHandler(string str);
2- define an event based on the previously defined delegate:
public static event CustomeEventHandler ReadLine;
3- create an event handler:
static void OnLineRead(string currentLine)
{
if (ReadLine != null)
ReadLine(currentLine);
}
4- raise your event using the event handler (just call it wherever you want the event to be raised).
Take the following C# class:
c1 {
event EventHandler someEvent;
}
If there are a lot of subscriptions to c1's someEvent event and I want to clear them all, what is the best way to achieve this? Also consider that subscriptions to this event could be/are lambdas/anonymous delegates.
Currently my solution is to add a ResetSubscriptions() method to c1 that sets someEvent to null. I don't know if this has any unseen consequences.
From within the class, you can set the (hidden) variable to null. A null reference is the canonical way of representing an empty invocation list, effectively.
From outside the class, you can't do this - events basically expose "subscribe" and "unsubscribe" and that's it.
It's worth being aware of what field-like events are actually doing - they're creating a variable and an event at the same time. Within the class, you end up referencing the variable. From outside, you reference the event.
See my article on events and delegates for more information.
Add a method to c1 that will set 'someEvent' to null.
public class c1
{
event EventHandler someEvent;
public ResetSubscriptions() => someEvent = null;
}
class c1
{
event EventHandler someEvent;
ResetSubscriptions() => someEvent = delegate { };
}
It is better to use delegate { } than null to avoid the null ref exception.
The best practice to clear all subscribers is to set the someEvent to null by adding another public method if you want to expose this functionality to outside. This has no unseen consequences. The precondition is to remember to declare SomeEvent with the keyword 'event'.
Please see the book - C# 4.0 in the nutshell, page 125.
Some one here proposed to use Delegate.RemoveAll method. If you use it, the sample code could follow the below form. But it is really stupid. Why not just SomeEvent=null inside the ClearSubscribers() function?
public void ClearSubscribers ()
{
SomeEvent = (EventHandler) Delegate.RemoveAll(SomeEvent, SomeEvent);
// Then you will find SomeEvent is set to null.
}
Setting the event to null inside the class works. When you dispose a class you should always set the event to null, the GC has problems with events and may not clean up the disposed class if it has dangling events.
You can achieve this by using the Delegate.Remove or Delegate.RemoveAll methods.
Conceptual extended boring comment.
I rather use the word "event handler" instead of "event" or "delegate". And used the word "event" for other stuff. In some programming languages (VB.NET, Object Pascal, Objective-C), "event" is called a "message" or "signal", and even have a "message" keyword, and specific sugar syntax.
const
WM_Paint = 998; // <-- "question" can be done by several talkers
WM_Clear = 546;
type
MyWindowClass = class(Window)
procedure NotEventHandlerMethod_1;
procedure NotEventHandlerMethod_17;
procedure DoPaintEventHandler; message WM_Paint; // <-- "answer" by this listener
procedure DoClearEventHandler; message WM_Clear;
end;
And, in order to respond to that "message", a "event handler" respond, whether is a single delegate or multiple delegates.
Summary:
"Event" is the "question", "event handler (s)" are the answer (s).
Remove all events, assume the event is an "Action" type:
Delegate[] dary = TermCheckScore.GetInvocationList();
if ( dary != null )
{
foreach ( Delegate del in dary )
{
TermCheckScore -= ( Action ) del;
}
}
This is my solution:
public class Foo : IDisposable
{
private event EventHandler _statusChanged;
public event EventHandler StatusChanged
{
add
{
_statusChanged += value;
}
remove
{
_statusChanged -= value;
}
}
public void Dispose()
{
_statusChanged = null;
}
}
You need to call Dispose() or use using(new Foo()){/*...*/} pattern to unsubscribe all members of invocation list.
Instead of adding and removing callbacks manually and having a bunch of delegate types declared everywhere:
// The hard way
public delegate void ObjectCallback(ObjectType broadcaster);
public class Object
{
public event ObjectCallback m_ObjectCallback;
void SetupListener()
{
ObjectCallback callback = null;
callback = (ObjectType broadcaster) =>
{
// one time logic here
broadcaster.m_ObjectCallback -= callback;
};
m_ObjectCallback += callback;
}
void BroadcastEvent()
{
m_ObjectCallback?.Invoke(this);
}
}
You could try this generic approach:
public class Object
{
public Broadcast<Object> m_EventToBroadcast = new Broadcast<Object>();
void SetupListener()
{
m_EventToBroadcast.SubscribeOnce((ObjectType broadcaster) => {
// one time logic here
});
}
~Object()
{
m_EventToBroadcast.Dispose();
m_EventToBroadcast = null;
}
void BroadcastEvent()
{
m_EventToBroadcast.Broadcast(this);
}
}
public delegate void ObjectDelegate<T>(T broadcaster);
public class Broadcast<T> : IDisposable
{
private event ObjectDelegate<T> m_Event;
private List<ObjectDelegate<T>> m_SingleSubscribers = new List<ObjectDelegate<T>>();
~Broadcast()
{
Dispose();
}
public void Dispose()
{
Clear();
System.GC.SuppressFinalize(this);
}
public void Clear()
{
m_SingleSubscribers.Clear();
m_Event = delegate { };
}
// add a one shot to this delegate that is removed after first broadcast
public void SubscribeOnce(ObjectDelegate<T> del)
{
m_Event += del;
m_SingleSubscribers.Add(del);
}
// add a recurring delegate that gets called each time
public void Subscribe(ObjectDelegate<T> del)
{
m_Event += del;
}
public void Unsubscribe(ObjectDelegate<T> del)
{
m_Event -= del;
}
public void Broadcast(T broadcaster)
{
m_Event?.Invoke(broadcaster);
for (int i = 0; i < m_SingleSubscribers.Count; ++i)
{
Unsubscribe(m_SingleSubscribers[i]);
}
m_SingleSubscribers.Clear();
}
}