Question regarding Events in John Skeet's book C# in Depth - c#

I'm studying C# Events on this link and am a little lost on when the following code is called in the context of Main()
/// <summary>
/// Raises the SomeEvent event
/// </summary>
protected virtual OnSomeEvent(EventArgs e)
{
SomeEventHandler handler;
lock (someEventLock)
{
handler = someEvent;
}
if (handler != null)
{
handler (this, e);
}
}
It's code that is right above the sentence
"You could use a single lock for all your events"
Question:
How or when does "OnSomeEvent" get called? I'm not asking about variable locking (as-is the context of the code sample) rather, I'm asking when does the protected virtual method pasted above get called?

The class calls OnSomeEvent when it wants to fire off the event.

Related

Raising events on separate thread

I am developing a component which needs to process the live feed and broadcast the data to the listeners in pretty fast manner ( with about 100 nano second level accuracy, even less than that if I can do that) Currently I am raising an event from my code which subscriber can subscribe to. However because in C# event handlers run on the same thread which raises the event, my thread which raises the event will be blocked until all subscribers finish processing the event. I do not have control on subscribers' code, so they can possibly do any time consuming operations in event handler, which may block the thread which is broadcasting.
What can I do so that I can broadcast the data to other subscribers but can still broadcast the stuff quite fast??
100 ns is a very tough target to hit. I believe it will take a deep understanding of what you're doing and why to hit that kind of performance.
However, asynchronously invoking event subscribers is pretty easy to solve.
It's already answered here by, who else, Jon Skeet.
foreach (MyDelegate action in multicast.GetInvocationList())
{
action.BeginInvoke(...);
}
edit:
I should also mention that you need to be running on a real-time operating system to give tight performance guarantees to your users.
It seems like you are looking for tasks. The following is an extension method i wrote for my job that can asynchronously invokes an event so that every event handler is on their own thread. I can't comment on its speed since that has never been a requirement for me.
UPDATE
Based on the comments i adjusted it so that only one task is created to call all of the subscribers
/// <summary>
/// Extension method to safely encapsulate asynchronous event calls with checks
/// </summary>
/// <param name="evnt">The event to call</param>
/// <param name="sender">The sender of the event</param>
/// <param name="args">The arguments for the event</param>
/// <param name="object">The state information that is passed to the callback method</param>
/// <remarks>
/// This method safely calls the each event handler attached to the event. This method uses <see cref="System.Threading.Tasks"/> to
/// asynchronously call invoke without any exception handling. As such, if any of the event handlers throw exceptions the application will
/// most likely crash when the task is collected. This is an explicit decision since it is really in the hands of the event handler
/// creators to make sure they handle issues that occur do to their code. There isn't really a way for the event raiser to know
/// what is going on.
/// </remarks>
[System.Diagnostics.DebuggerStepThrough]
public static void AsyncSafeInvoke( this EventHandler evnt, object sender, EventArgs args )
{
// Used to make a temporary copy of the event to avoid possibility of
// a race condition if the last subscriber unsubscribes
// immediately after the null check and before the event is raised.
EventHandler handler = evnt;
if (handler != null)
{
// Manually calling all event handlers so that we could capture and aggregate all the
// exceptions that are thrown by any of the event handlers attached to this event.
var invocationList = handler.GetInvocationList();
Task.Factory.StartNew(() =>
{
foreach (EventHandler h in invocationList)
{
// Explicitly not catching any exceptions. While there are several possibilities for handling these
// exceptions, such as a callback, the correct place to handle the exception is in the event handler.
h.Invoke(sender, args);
}
});
}
}
You can use these simple extension methods on your event handlers:
public static void Raise<T>(this EventHandler<T> handler, object sender, T e) where T : EventArgs {
if (handler != null) handler(sender, e);
}
public static void Raise(this EventHandler handler, object sender, EventArgs e) {
if (handler != null) handler(sender, e);
}
public static void RaiseOnDifferentThread<T>(this EventHandler<T> handler, object sender, T e) where T : EventArgs {
if (handler != null) Task.Factory.StartNewOnDifferentThread(() => handler.Raise(sender, e));
}
public static void RaiseOnDifferentThread(this EventHandler handler, object sender, EventArgs e) {
if (handler != null) Task.Factory.StartNewOnDifferentThread(() => handler.Raise(sender, e));
}
public static Task StartNewOnDifferentThread(this TaskFactory taskFactory, Action action) {
return taskFactory.StartNew(action: action, cancellationToken: new CancellationToken());
}
Usage:
public static Test() {
myEventHandler.RaiseOnDifferentThread(null, EventArgs.Empty);
}
The cancellationToken is necessary to guarantee StartNew() actually uses a different thread, as explained here.
I can't speak to if this will reliably meet the 100ns requirement but here's an alternative where you'd provide the end user with a way to provide you a ConcurrentQueue that you would fill and they could listen to on a separate thread.
class Program
{
static void Main(string[] args)
{
var multicaster = new QueueMulticaster<int>();
var listener1 = new Listener(); //Make a couple of listening Q objects.
listener1.Listen();
multicaster.Subscribe(listener1);
var listener2 = new Listener();
listener2.Listen();
multicaster.Subscribe(listener2);
multicaster.Broadcast(6); //Send a 6 to both concurrent Queues.
Console.ReadLine();
}
}
//The listeners would run on their own thread and poll the Q like crazy.
class Listener : IListenToStuff<int>
{
public ConcurrentQueue<int> StuffQueue { get; set; }
public void Listen()
{
StuffQueue = new ConcurrentQueue<int>();
var t = new Thread(ListenAggressively);
t.Start();
}
void ListenAggressively()
{
while (true)
{
int val;
if(StuffQueue.TryDequeue(out val))
Console.WriteLine(val);
}
}
}
//Simple class that allows you to subscribe a Queue to a broadcast event.
public class QueueMulticaster<T>
{
readonly List<IListenToStuff<T>> _subscribers = new List<IListenToStuff<T>>();
public void Subscribe(IListenToStuff<T> subscriber)
{
_subscribers.Add(subscriber);
}
public void Broadcast(T value)
{
foreach (var listenToStuff in _subscribers)
{
listenToStuff.StuffQueue.Enqueue(value);
}
}
}
public interface IListenToStuff<T>
{
ConcurrentQueue<T> StuffQueue { get; set; }
}
Since given the fact that you can't hold up processing on other listeners this means multiple threads. Having dedicated listening threads on the listeners seems like a reasonable approach to try, and the concurrent queue seems like a decent delivery mechanism. In this implementation it's just constantly polling, but you could probably use thread signaling to reduce the cpu load using something like AutoResetEvent.
Signals and shared memory are very fast. You could send a separate signal to tell applications to read a message from a shared-memory location. Of course, the signal is still an event that your application has to consume on a high-priority thread if you want low latency. I would include a time-tag in the data so the receiver can compensate for the inevitable latency.

Why is my event throwing a null error?

For some reason my event is throwing a null error. I don't see anything wrong.
here is the event
public delegate void connectionSuccess(bool success);
public event connectionSuccess Connection;
then in a function i have this witch throws the null error
Connection(true);
Edit* function in another class that calls the connection function
Server.Connection += onConnection;
Server.startConnection();
If it is not connected, it is null.
Try this instead:
var h = Connection;
if ( h!=null )
{
h(true);
}
I'm assigning to a (local) variable first in order to overcome multi-threading scenarios where there are modifications between checking for null and calling.
I.e. the following would not be thread-safe:
if ( Connection!=null )
{
Connection(true); // Here, could already be null, again.
}
You need to check and make sure something is actually subscribed to the event before you invoke it.
if(Connection != null)
Connection(true);
Because you have no subscribers yet. When an event has no subscribers it becomes null. You have two options to solve this (I prefer the second).
Option 1:
if (Connection != null)
Connection(true);
Option 2:
public event connectionSuccess Connection = delegate { };
You are getting the error because a null reference exception will be thrown if there is the null delegate reference! So, it is necessary to check the delegate reference.
It is a good practice to create an event invocator - helper method. It simplifies calling the event handlers.
For example, let's take a look at Book class which implements INotifyPropertyChanged interface:
class Book : INotifyPropertyChanged
{
private string _name;
public string Name
{
get { return _name; }
set
{
if (_name == value)
return;
_name = value;
OnPropertyChanged("Name");
}
}
#region Implementation of INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Event invocator.
/// </summary>
/// <param name="propertyName">Property name.</param>
private void OnPropertyChanged(string propertyName)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
More detailed information about the implementation of event invocators is here: Events and Races.
You should check the initialization of your objects. While your code does make it look like everything is in the same class, I'm not sure why you would go through the headache of creating events instead of just calling the method.
HOWEVER, if your raising the event in one class and attempting to handle it in another, you may run into the same thing that I did. Let me explain...
MDIParent - Contains the instantiation code for the child form. Also has the code to wire the event handler of the child to the code on the MDIParent.
Form x = new MyTestForm();
x.OnMyEvent += this.HandleEvent(myEventArgs);
MDIChild - Contains the code that we use to create the event and actually trigger it.
public MyTestForm()
{
public event EventHappened MyEventHandler;
}
Later in the code, we actually raise the event.
MyEventHandler(new MyEventArgs(this, "some message");
The problem that I was having with all of my event handlers, which we were using to update a StatusBar, was that the wiring up of the event wasn't happening until the form was completely initialized. This means that all of the work in setting up the form was complete by the time we actually wired the event TO something!
How did I get around this, you ask? Well, I moved all of the initialization code into a separate method and out of the constructor. We call the constructor to create an instance of the form, wire the events up, and THEN run through all of the form's creation tasks.
Hope that this helps someone! I spent days trying to figure out why my events were null when I could plainly see that they were assigned!

Why assign a handler to an event before calling it?

Basically, I've seen this used all to often:
public event MyEventHandler MyEvent;
private void SomeFunction()
{
MyEventHandler handler = this.MyEvent;
if (handler != null)
{
handler(this, new MyEventArgs());
}
}
When it could just as easily be done like so:
public event MyEventHandler MyEvent;
private void SomeFunction()
{
if (MyEvent != null)
{
MyEvent(this, new MyEventArgs());
}
}
So, am I missing something? Is there some reason people assign the event to a handler, then raise the handler instead of the event itself? Is it just "best practice"?
The assignment to a local variable ensures that if the event gets unregistered between the if and the actual invocation, the invocation list will not be null (since the variable will have a copy of the original invocation list).
This can easily happen in multithreaded code, where between checking for a null and firing the event it may be unregistered by another thread.
See this SO question and answers.
Thread safety.
What happens if between the time you check if MyEvent is null and you fire MyEvent, another thread comes along and unsubscribes from the event?

In C#, why can't I test if a event handler is null anywhere outside of the class that it's defined?

I am sure that I am just not understanding something fundamental about events and/or delegates in C#, but why can't I do the Boolean tests in this code sample:
public class UseSomeEventBase {
public delegate void SomeEventHandler(object sender, EventArgs e);
public event SomeEventHandler SomeEvent;
protected void OnSomeEvent(EventArgs e) {
// CANONICAL WAY TO TEST EVENT. OF COURSE, THIS WORKS.
if (SomeEvent != null) SomeEvent(this, e);
}
}
public class UseSomeEvent : UseSomeEventBase {
public bool IsSomeEventHandlerNull() {
// "LEFT HAND SIDE" COMPILER ERROR
return SomeEvent == null;
}
}
class Program {
static void Main(string[] args) {
var useSomeEvent = new UseSomeEvent();
useSomeEvent.SomeEvent +=new UseSomeEventBase.SomeEventHandler(FuncToHandle);
// "LEFT HAND SIDE" COMPILER ERROR
if (useSomeEvent.SomeEvent == null) {
}
var useSomeEventBase = new UseSomeEventBase();
useSomeEventBase.SomeEvent += new UseSomeEventBase.SomeEventHandler(FuncToHandle);
// "LEFT HAND SIDE" COMPILER ERROR
if (useSomeEventBase.SomeEvent == null) {
}
}
static void FuncToHandle(object sender, EventArgs e) { }
}
An event is really just an "add" operation and a "remove" operation. You can't get the value, you can't set the value, you can't call it - you can just subscribe a handler for the event (add) or unsubscribe one (remove). This is fine - it's encapsulation, plain and simple. It's up to the publisher to implement add/remove appropriately, but unless the publisher chooses to make the details available, subscribers can't modify or access the implementation-specific parts.
Field-like events in C# (where you don't specify the add/remove bits) hide this - they create a variable of a delegate type and an event. The event's add/remove implementations just use the variable to keep track of the subscribers.
Inside the class you refer to the variable (so you can get the currently subscribed delegates, execute them etc) and outside the class you refer to the event itself (so only have add/remove abilities).
The alternative to field-like events is where you explicitly implement the add/remove yourself, e.g.
private EventHandler clickHandler; // Normal private field
public event EventHandler Click
{
add
{
Console.WriteLine("New subscriber");
clickHandler += value;
}
remove
{
Console.WriteLine("Lost a subscriber");
clickHandler -= value;
}
}
See my article on events for more information.
Of course the event publisher can also make more information available - you could write a property like ClickHandlers to return the current multi-cast delegate, or HasClickHandlersto return whether there are any or not. That's not part of the core event model though.
You can easily use a very simple approach here to not repeatedly subscribe to an event.
Either of the 2 approaches below can be used:
Flag approach : _getWarehouseForVendorCompletedSubscribed is a private variable initialized to false.
if (!_getWarehouseForVendorCompletedSubscribed)
{
_serviceClient.GetWarehouseForVendorCompleted += new EventHandler<GetWarehouseForVendorCompletedEventArgs>(_serviceClient_GetWarehouseForVendorCompleted);
_getWarehouseForVendorCompletedSubscribed = true;
}
Unsubscribe Approach :Include an unsubscribe everytime you want to subscribe.
_serviceClient.GetWarehouseForVendorCompleted -= new
EventHandler<GetWarehouseForVendorCompletedEventArgs>
(_serviceClient_GetWarehouseForVendorCompleted);
_serviceClient.GetWarehouseForVendorCompleted += new
EventHandler<GetWarehouseForVendorCompletedEventArgs>
(_serviceClient_GetWarehouseForVendorCompleted);
Here the answer:
using System;
delegate void MyEventHandler();
class MyEvent
{
string s;
public event MyEventHandler SomeEvent;
// This is called to raise the event.
public void OnSomeEvent()
{
if (SomeEvent != null)
{
SomeEvent();
}
}
public string IsNull
{
get
{
if (SomeEvent != null)
return s = "The EventHandlerList is not NULL";
else return s = "The EventHandlerList is NULL"; ;
}
}
}
class EventDemo
{
// An event handler.
static void Handler()
{
Console.WriteLine("Event occurred");
}
static void Main()
{
MyEvent evt = new MyEvent();
// Add Handler() to the event list.
evt.SomeEvent += Handler;
// Raise the event.
//evt.OnSomeEvent();
evt.SomeEvent -= Handler;
Console.WriteLine(evt.IsNull);
Console.ReadKey();
}
}
Here's a slightly different question
What value is there in testing an externally defined event for null?
As an external consumer of an event you can only do 2 operations
Add a handler
Remove a handler
The null or non-nullness of the event has no bearing on these 2 actions. Why do you want to run a test which provides no perceivable value?
It's a rule in place when using the 'event' keyword. When you create an event, you are restricting outside class interaction with the delegate to a "subscribe / unsubscribe" relationship, this includes cases of inheritance. Remember an event is essentially a property, but for method calls, it isn't really an object itself, so really it looks more like this:
public event SomeEventHandler SomeEvent
{
add
{
//Add method call to delegate
}
remove
{
//Remove method call to delegate
}
}
You'd have to do that from the base class. That's the exact reason that you did this:
protected void OnSomeEvent(EventArgs e) {
// CANONICAL WAY TO TEST EVENT. OF COURSE, THIS WORKS.
if (SomeEvent != null) SomeEvent(this, e);
}
You can't access events from a derived class. Also, you should make that method virtual, so that it can be overridden in a derived class.
Publisher of the event implicitly overload only += and -= operations, and other operations are not implemented in the publisher because of the obvious reasons as explained above, such as don't want to give control to subscriber to change events.
If we want to validate if a particular event is subscribed in the subscriber class, better publisher will set a flag in its class when event is subscriber and clear the flag when it is unsubscriber.
If subscriber can access the flag of publisher, very easily identifiable whether the particular event is subscriber or not by checking the flag value.

C#: Thread-safe events

Is the implementation below thread-safe? If not what am I missing? Should I have the volatile keywords somewhere? Or a lock somewhere in the OnProcessingCompleted method? If so, where?
public abstract class ProcessBase : IProcess
{
private readonly object completedEventLock = new object();
private event EventHandler<ProcessCompletedEventArgs> ProcessCompleted;
event EventHandler<ProcessCompletedEventArgs> IProcess.ProcessCompleted
{
add
{
lock (completedEventLock)
ProcessCompleted += value;
}
remove
{
lock (completedEventLock)
ProcessCompleted -= value;
}
}
protected void OnProcessingCompleted(ProcessCompletedEventArgs e)
{
EventHandler<ProcessCompletedEventArgs> handler = ProcessCompleted;
if (handler != null)
handler(this, e);
}
}
Note: The reason why I have private event and explicit interface stuff, is because it is an abstract base class. And the classes that inherit from it shouldn't do anything with that event directly. Added the class wrapper so that it is more clear =)
You need to lock when you fetch the handler too, otherwise you may not have the latest value:
protected void OnProcessingCompleted(ProcessCompletedEventArgs e)
{
EventHandler<ProcessCompletedEventArgs> handler;
lock (completedEventLock)
{
handler = ProcessCompleted;
}
if (handler != null)
handler(this, e);
}
Note that this doesn't prevent a race condition where we've decided we're going to execute a set of handlers and then one handler unsubscribed. It will still be called, because we've fetched the multicast delegate containing it into the handler variable.
There's not a lot you can do about this, other than making the handler itself aware that it shouldn't be called any more.
It's arguably better to just not try to make the events thread-safe - specify that the subscription should only change in the thread which will raise the event.
There is no need for the private ProcessCompleted member to be an event - it could just be a field: private EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - inside the class it always goes straight to the field, so the event stuff is lost anyway.
The approach you've shown with an explicit lock object isn't much more thread-safe than just having a field-like event (i.e. public event EventHandler<ProcessCompletedEventArgs> ProcessCompleted; - the only difference is that you aren't locking "this" (which is a good thing - you should ideally avoid locking on this).. The "handler variable" approach is the right one, but there are still side-effects you should be aware of.

Categories

Resources