How is this code going to behave through processing time ? (i.e, how synchronous is it ?)
public delegate void FooDelegate(bytes[] data);
public event FooDelegate FooEvent;
FooEvent += new FooDelegate(Process_X);
FooEvent += new FooDelegate(Process_Y);
FooEvent += new FooDelegate(Process_Z);
while (receiving)
{
byte[] data = getRealTimeData();
StopWatch.Start();
FooEvent(data);
StopWatch.Stop();
Console.Write(StopWatch.Elapsed.Millisec));
StopWatch.Reset();
}
I have a couple of questions :
Will the call to FooEvent result in calling each subscription process sequentially/synchornously ? (Probably yes...)
Assuming each Process_N takes a long while to finish, will the call to each one block the chain (i.e the call to the next one) until it has finished ? If this is true, How to make the event call Processes X, Y, Z in a parallel fashion an then wait for all of them to finish, rather than calling them one by one and sequentially waiting for each one to finish ?
A few confirmations :
If the number of subscribers gets very high, I guess the Time printed by the StopWatch will get higher
If the processing logic in Process_N gets heavier, it will also affect the Time printed by the StopWatch
It looks like you'd benefit from parallelisation of your event handlers, as they will indeed execute sequentially and synchronously.
To create your custom event handlers you might write:
public event FooDelegate FooEvent
{
add
{
// code to add an event handler
}
remove
{
// code to remove an event handler
}
}
See the following questions for more information on what to do with the custom event handlers:
Events with Task Parallel Library for .NET 4+
How to process events in parallel
Parallel event handling in C#
etc.
and Jon Skeet's page on delegates and events.
1: yes
2: yes
It has to events might return results.
But: you should implement your event-handlers in a way so that they don't take long to run!
If they have to do heavy lifting consider running the computation in a task that get's started in your event-handeler.
Related
There are two parts to this question:
Does raising an event block the thread, or does it start execution of EventHandlers asynchronously and the thread goes continues on at the same time?
Are the individual EventHandlers (subscribed to the event) run synchronously one after another, or are they run asynchronously with no guarantee that others aren't running at the same time?
This is a general answer and reflects the default behavior:
Yes, it blocks the thread, if the methods subscribing to the event are not asynchronous.
They are executed one after the other. This has another twist: If one event handler throws an exception, the event handlers not yet executed will not be executed.
Having said that, every class that provides events can choose to implement its event asynchronously. IDesign provides a class called EventsHelper that simplifies this.
[Note] this link requires you to provide an e-mail address to download EventsHelper class. (I am not affiliated in any way)
Yes, they are synchronous.
To answer your questions:
Raising an event does block the thread if the event handlers are all implemented synchronously.
The event handlers are executed sequentially, one after another, in the order they are subscribed to the event.
I too was curious about the internal mechanism of event and its related operations. So I wrote a simple program and used ildasm to poke around its implementation.
The short answer is
there's no asynchronous operation involved in subscribing or invoking the events.
event is implemented with a backing delegate field of the same delegate type
subscribing is done with Delegate.Combine()
unsubscribing is done with Delegate.Remove()
Invoking is done by simply invoking the final combined delegate
Here's what I did. The program I used:
public class Foo
{
// cool, it can return a value! which value it returns if there're multiple
// subscribers? answer (by trying): the last subscriber.
public event Func<int, string> OnCall;
private int val = 1;
public void Do()
{
if (OnCall != null)
{
var res = OnCall(val++);
Console.WriteLine($"publisher got back a {res}");
}
}
}
public class Program
{
static void Main(string[] args)
{
var foo = new Foo();
foo.OnCall += i =>
{
Console.WriteLine($"sub2: I've got a {i}");
return "sub2";
};
foo.OnCall += i =>
{
Console.WriteLine($"sub1: I've got a {i}");
return "sub1";
};
foo.Do();
foo.Do();
}
}
Here's Foo's implementation:
Note that there is a field OnCall and an event OnCall. The field OnCall is obviously the backing property. And it's merely a Func<int, string>, nothing fancy here.
Now the interesting parts are:
add_OnCall(Func<int, string>)
remove_OnCall(Func<int, string>)
and how OnCall is invoked in Do()
How is Subscribing and Unsubscribing Implemented?
Here's the abbreviated add_OnCall implementation in CIL. The interesting part is it uses Delegate.Combine to concatenate two delegates.
.method public hidebysig specialname instance void
add_OnCall(class [mscorlib]System.Func`2<int32,string> 'value') cil managed
{
// ...
.locals init (class [mscorlib]System.Func`2<int32,string> V_0,
class [mscorlib]System.Func`2<int32,string> V_1,
class [mscorlib]System.Func`2<int32,string> V_2)
IL_0000: ldarg.0
IL_0001: ldfld class [mscorlib]System.Func`2<int32,string> ConsoleApp1.Foo::OnCall
// ...
IL_000b: call class [mscorlib]System.Delegate [mscorlib]System.Delegate::Combine(class [mscorlib]System.Delegate,
class [mscorlib]System.Delegate)
// ...
} // end of method Foo::add_OnCall
Likewise, Delegate.Remove is used in remove_OnCall.
How is an event invoked?
To invoke OnCall in Do(), it simply calls the final concatenated delegate after loading the arg:
IL_0026: callvirt instance !1 class [mscorlib]System.Func`2<int32,string>::Invoke(!0)
How exactly does a subscriber subscribe to an event?
And finally, in Main, not suprisingly, subscribing to the OnCall event is done by calling add_OnCall method on the Foo instance.
The delegates subscribed to the event are invoked synchronously in the order they were added. If one of the delegates throws an exception, the ones following will not be called.
Since events are defined with multicast delegates, you can write your own firing mechanism using
Delegate.GetInvocationList();
and invoking the delegates asynchronously;
Events are just arrays of delegates. As long as delegate call is synchronous, events are also synchronous.
In general, events are synchronous. However there are some exceptions, such as System.Timers.Timer.Elapsed event being raised on a ThreadPool thread if SyncronisingObject is null.
Docs: http://msdn.microsoft.com/en-us/library/system.timers.timer.elapsed.aspx
Events in C# run synchronously (in both cases), as long as you don't start a second thread manually.
Events are synchronous. This is why the event lifecycle works the way it does. Inits happen before loads, loads happen before renders etc.
If no handler is specified for an event, the cycle just blazes through. If more than one handler is specified, they will be called in order and one can't continue until the other is completely finished.
Even asynchronous calls are synchronous to a degree. It would be impossible to call the end before the begin is completed.
I have an integration test, where I trigger things by sending off an event. Then a couple of asynchronous things happen, and I expect a specific number of events to be raised by this.
My test code shall wait until this number of events were raised. I did this with a callback subscription to this event and a wait handle. Basically
private AutoResetEvent thingsChangedEventOccurred = new AutoResetEvent(false);
private void OnThingsChangedEventOccurred(ThingsChangedEventData thingsChangedEventData)
{
this.thingsChangedEventOccurred.Set();
}
private void WaitForThisNumberOfThingsChangedEvents(int numberOfEventsToWaitFor)
{
for (int eventsCaptured = 0; eventsCaptured < numberOfEventsToWaitFor; eventsCaptured++)
{
Assert.IsTrue(this.thingsChangedEventOccurred.WaitOne(60000));
}
}
And somewhere after I sent off the events that start things I call the WaitFor.. Method.
I realize now that this implementation has its problems with threading. I assume the AutoResetEvent can only count to one. Any ideas or patterns on how to make this thread safe?
I thought about making the eventsCaptured a field... butwell, that is kind of uncool for other reasons.
I think you're looking for CountdownEvent.
Basically, you initialize a CountdownEvent with the number of events you're expecting. Then, as each event occurs, the code signals the CountdownEvent, which will become set after it's been signaled the expected number of times.
It's a pretty handy thing. Definitely check it out.
I imagine this may be marked as repetitious and closed, but I cannot for the life of me find a clear, concise answer to this question. All the replies and resources deal almost exclusively with Windows Forms and utilizing pre-built utility classes such as BackgroundWorker. I would very much like to understand this concept at its core, so I can apply the fundamental knowledge to other threading implementations.
A simple example of what I would like to achieve:
//timer running on a seperate thread and raising events at set intervals
//incomplete, but functional, except for the cross-thread event raising
class Timer
{
//how often the Alarm event is raised
float _alarmInterval;
//stopwatch to keep time
Stopwatch _stopwatch;
//this Thread used to repeatedly check for events to raise
Thread _timerThread;
//used to pause the timer
bool _paused;
//used to determine Alarm event raises
float _timeOfLastAlarm = 0;
//this is the event I want to raise on the Main Thread
public event EventHandler Alarm;
//Constructor
public Timer(float alarmInterval)
{
_alarmInterval = alarmInterval;
_stopwatch = new Stopwatch();
_timerThread = new Thread(new ThreadStart(Initiate));
}
//toggles the Timer
//do I need to marshall this data back and forth as well? or is the
//_paused boolean in a shared data pool that both threads can access?
public void Pause()
{
_paused = (!_paused);
}
//little Helper to start the Stopwatch and loop over the Main method
void Initiate()
{
_stopwatch.Start();
while (true) Main();
}
//checks for Alarm events
void Main()
{
if (_paused && _stopwatch.IsRunning) _stopwatch.Stop();
if (!_paused && !_stopwatch.IsRunning) _stopwatch.Start();
if (_stopwatch.Elapsed.TotalSeconds > _timeOfLastAlarm)
{
_timeOfLastAlarm = _stopwatch.Elapsed.Seconds;
RaiseAlarm();
}
}
}
Two questions here; primarily, how do i get the event to the main thread to alert the interested parties of the Alarm event.
Secondarily, regarding the Pause() method, which will be called by an object running on the main thread; can i directly manipulate the Stopwatch that was created on the background thread by calling _stopwatch.start()/_stopwatch.stop(). If not, can the main thread adjust the _paused boolean as illustrated above such that the background thread can then see the new value of _paused and use it?
I swear, I've done my research, but these (fundamental and critical) details have not made themselves clear to me yet.
Disclaimer: I am aware that there are classes available that will provide the exact particular functionality that I am describing in my Timer class. (In fact, I believe the class is called just that, Threading.Timer) However, my question is not an attempt to help me implement the Timer class itself, rather understand how to execute the concepts that drive it.
Note: im writing this here because theres not enough space on comments, this is of course not a complete, nor half a complete answer:
I've always used Events to signal unrelated code to do something, so that was how I described my intent. Forgive me though, I'm not sure I see the difference between marshaling and event versus marshaling another type of data (signal).
Conceptually both can be treated as events. The difference between using provided sync/signalining objects and trying to implement something like this by urself, is who and how gets the job done.
An event in .net is just a delegate, a list of pointers to methods that should be executed when the provider of the event fires it.
What youre talking about (marshalling the event), if i understand you correctly, is sharing the event object when something happens, while the concept of signalig usually talks about an object which is shared to start with, and both threads "know" something happened by checking its state either manualy or automatily (relying on provided tools by both .net and windows).
In the most basic scenario, you can implement such a signaling concept by using a boolean variable, with one thread constantly looping to check if the value of the boolean is true, and another setting to such, as a way to signal something happend. The different signaling tools provided by .NET do this in a less resource-wasting maner, by also not executing the waiting thread, as long as theres no signal (the boolean equals to false), but conceptually, it is the same idea.
You cannot magically execute code on an existing thread.
Instead, you need the existing thread to explicitly execute your code, using a thread-safe data structure to tell it what to do.
This is how Control.Invoke works (which is in turn how BackgroundWorker works).
WiinForms runs a message loop in Application.Run() which looks roughly like this:
while(true) {
var message = GetMessage(); //Windows API call
ProcessMessage(message);
}
Control.Invoke() sends a Windows message (using thread-safe message passing code within Windows) telling it to run your delegate. ProcessMessage (which executes on the UI thread) will catch that message and execute the delegate.
If you want to do this yourself, you will need to write your own loop. You can use the new thread-safe Producer-Consumer collections in .Net 4.0 for this, or you can use a delegate field (with Interlocked.CompareExchange) and an AutoResetEvent and do it yourself.
In C#, when using the System.Timers.Timer, can the ElapsedEvent run if the previous one has not finished?
Imagine I have an event that takes longer to complete than I anticipated, and the timer's interval is up, before execution has finished. What happens then?
From what I could read on MSDN, System.Timers run on the threadpool, where as Windows Timers run single threaded.
I am concerned that I will accidently run two (or more!) events at the same time.
Yes, the Elapsed event will be fired again.
Reading carefully the MSDN Documentation that says:
If the SynchronizingObject property is Nothing, the Elapsed event is raised on a ThreadPool thread. If the processing of the Elapsed event lasts longer than Interval, the event might be raised again on another ThreadPool thread. In this situation, the event handler should be reentrant.
Also using the Stop method doesn't ensure the end of Elapsed event because the Stop event could be queued in an different Thread respect the Interval event.
Again reading the MSDN clarifies how to handle this situation
Yes they can.
Two possible solutions:
Specify a SynchonizingObject in your timer to prevent multiple threads from running at once. The problem here is that if your implementation takes longer than the timer timeout, then you calls will back up.
Stop the timer at the start of your delegate, and restart it again at the end. This seems to be a more common pattern, but means that your events will not fire exactly on time unless you do some timing inside your callback. This may or may not be a problem.
Yes, absolutely. Here's a short but complete program to demonstrate that:
using System;
using System.Threading;
using Timer = System.Timers.Timer;
class Test
{
static void Main()
{
Timer timer = new Timer(1000);
timer.Elapsed += ElapsedHandler;
timer.Enabled = true;
Thread.Sleep(10000);
timer.Enabled = false;
}
static void ElapsedHandler(object sender, EventArgs e)
{
int id = Thread.CurrentThread.ManagedThreadId;
Console.WriteLine("{0}: Starting to sleep", id);
Thread.Sleep(5000);
Console.WriteLine("{0}: Exiting", id);
}
}
How you deal with it is up to you. You could:
Use the SynchronizingObject property to get more control
Keep some sort of atomic or counter to say whether or not to really process the "tick"
Take some sort of "abortive" action
... it really depends on your situation.
in my class i use a BackgroundWorker. at some point i need to cancel the asynchronous operation that can be in progress and start another one immediately. the code follows. one thing that i am not sure about is the race condition that can occur if the worker completes right before i assign my lambda to RunWorkerCompleted event. if this happens my lambda will never get called. the comment in the code shows this place. any comments on how to handle this?
thanks
konstantin
if (this.worker.IsBusy)
{
RunWorkerCompletedEventHandler f = null;
f = (s, v) =>
{
this.RunWorkerCompleted -= f;
this.worker.RunWorkerAsync();
};
// what if worker completes right before the following statement?
this.worker.RunWorkerCompleted += f;
this.worker.CancelAsync();
}
else
{
this.worker.RunWorkerAsync();
}
As long as this code runs on the main thread then there is no race. A BGW can only complete when the RunWorkerCompleted event handler finished running. The handler cannot start running until the main thread re-enters the message loop.
There's another kind of race though, induced by the else clause. You let the BGW start without a RunWorkerCompleted event handler. Now it can complete asynchronously since it won't be blocked. Always subscribe the event, test e.Cancelled to know what happened.
You could just add the RunWorkerCompleted event handler once in the ctor and also add a bool member variable 'restart' to the class. Then you can write if(IsBusy) restart = true and in your handler you check if(restart) Run(). You can define restart as volatile to avoid race conditions in that case.
I think it is not a good practice to add and remove event handlers in your case.
Maybe i'm just not smart enough to understand your code. But in my world i would built up a Queue<Action> and fill in all jobs that have to be done.
Another thread (or BackgroundWorker) will take a look at this Queue and process all the jobs in the queue sequentially (like my answer here). Maybe this is not very elegant due to the pull-mode by using a Thread.Sleep(1) in a loop.
But this could be accomplished by creating a BindingQueue<T> that derived from Queue<T> and implements IBindingList. So you could just wait for such an event, dequeue and invoke an Action till the queue is empty and start over again.