How do I fire an event handler in a separate thread? - c#

I've created a service which will fire an event for each of the item in the list.
I've used a foreach loop to iterate through the list and trigger the event for each of the item in the list.
In order to improve the performance of the service,
It was suggested that i try to run the event handler in a separate thread.
I'm new to the concept of threading,
Can I get some suggestions on how I can run only the event handler on a separate thread? Should I create a separate thread for the each of the item in my list?
Any suggestions are welcome.
Here is my code:
public void UpdateMessages(){
foreach(var message in messages)
{
message.Received +=
TextMessage_MessageReceived;
}
}
private void RawMessage_MessageReceived(object sender, MessageEventArgs<TextMessage> e)
{
var msgText = sender as RealtimeTextMessage;
RawMessageList[msgText].SetMessageBytes(msgText);
}
In the code snippet I have the event handler RawMessage_MessageReceived which will perform the operation of extracting the bytes from the raw message.
I need to perform the event handling in a different thread since from what I understand about threading, a single thread will be responsible for raising the event for each message and simultaneously will be responsible for event handling of each event.
How can I write a separate thread to take care of the event handling part?

Related

awaitng async eventhandler does not waits the method to continue

I am developing a WinForms Application.
I created a custom Control (inheriting from Control class). It has its own Eventhandlers to allow the forms to observe some events.
public event EventHandler<TextBoxFilterEventArgs> DataGetFiltered;
My issues came when, inside the control,in some specific situations I perform a call to the registered receivers:
this.Enabled=false;
if (DataGetFiltered != null)
DataGetFiltered(this, new TextBoxFilterEventArgs(itemsFiltered));
this.Enabled=true;
You can see I set the control disabled/enabled before and after the call.
The form containing the control is registering some methods to that event in a async way:
txtFilter.DataGetFiltered += async (s, e) => await txtFilterByDesc_DataGetFiltered(s, e);
private async Task txtFilterByDesc_DataGetFiltered(object sender, TextBoxFilterEventArgs e)
{
await Task.Run(()=>/*some code*/);
}
What happens?
The control calls to the events handlers registered but it continues to run this.Enabled=true;without waiting previous call to finish( but it has been awaited!)
What's going on?
What happens?
After disabling control, your event handling code runs asynchronous delegate.
The delegate ultimately calls Task.Run and offloads some work to a thread pool thread.
Then delegate returns, and control becomes enabled again, but scheduled task still runs in background.
The control is a textbox that i want to get enabled/disabled during the handling of eventhandlers. I have to move that logic to the handler itself?
Short answer: yes.
More detailed answer: while you're using standard .NET event handling pattern, you have to move this logic into event handler. Event doesn't know about handlers implementation. They can be either synchronous, or asynchronous. So, all you can do is to let event handler to manage Enabled property.
Technically, you can invent some sort of asynchronous event handler, but, actually, you shouldn't. .NET developers know, that event delegate is of type EventHandler/EventHandler<T>. Custom event delegate type breaks well-known pattern.
I think it's because your event handler uses await, but your called method doesn't wait for the handler! So, you need to create your own event that returns Task, like the following:
public delegate Task DataGetFiltered(object sender, TextBoxFilterEventArgs e);
public event DataGetFiltered OnDataGetFiltered;
And in the called method:
if (null != this.OnDataGetFiltered)
{
var args = new TextBoxFilterEventArgs(itemsFiltered);
foreach (var handler in this.OnDataGetFiltered.GetInvocationList().Cast<DataGetFiltered>())
{
await handler(this, args);
}
}

Are c# events handled serially or in parallel?

For example, I have a class that fires an event, and 1000 subscribers to that event. Is a single thread used to fire each subscriber delegate one-by-one? Or does .Net use a thread pool to process some or all of the subscriptions in parallel?
As Tigran said, event invocation is serial. Even more if one of the subscribers throws an exception at some point the rest of them will not be triggered.
The easiest way to trigger an event in parallel will be
public event Action Event;
public void Trigger()
{
if (Event != null)
{
var delegates = Event.GetInvocationList();
Parallel.ForEach(delegates, d => d.DynamicInvoke());
}
}
This implementation will suffer from same problem in case of an exception.
As is, event are simple serial invocation. If you want you can run it in async way, but this is an implementation detail.
In short: there is no any built-in parallelization or async of standard .NET events, it's up to you to implement it.

Piggybacking data on EventArgs or sender for an EventHandler

I am writing a custom scheduler and as such I want to fire off whatever tasks are registered to be run at the current time, without taking so much time that the scheduler misses the next time slot. I have therefore created a thread that sleeps until the next scheduled event and then it wakes and runs that next event or events and then it sleeps again. Tasks are run as processes in the background so I can just set them up and fire them off as quickly as possible. In order to facilitate logging for the controlling process I keep an internal queue of tasks that upon waking, I consume as I fire off the processes, but I also want to have an EventHandler that can then finish the logging for that task by registering how long it took and whether it failed or succeeded once it exits.
Because I am using the Process.Process() class to execute the task in the background, there is no way (I can see) to pass my unique task reference through to the handler so I can finish the logging correctly. I am setting up my handler like the code below.
pTask = new Process();
pTask.Exited += new EventHandler(pTask_Exited);
I deliberately used the term piggyback in my title because in my research I came across a similar question which attracted one answer that said if you need to piggyback data on EventArgs, your design is flawed. I can accept my design may be flawed, but have not been able to find enlightenment as to how I should design it differently and more effectively. Any guidance is appreciated.
You can achieve this using lambdas as follows:
First define a method that will be run when the process exits. This will be instead of any event handler you are currently using, and performs the necessary logging etc.:
void ExitHandler(Process process, YourTaskInfo taskInfo) // YourTaskInfo is some class that contains data about the task that needs to be passed to the handler
{
Console.WriteLine("Process for task: {0} exited with code: {1}", taskInfo, process.ExitCode);
}
You can then attach this method to the Exited event handler as follows:
pTask.Exited += (s,e) => ExitHandler(pTask, taskInfo);
In this way, you can pass in your unique task reference (taskInfo) to the Exited handler, without worrying about any "piggybacking" etc. on the sender or EventArgs.
Get the data from the Process itself, which is passed as the sender:
void pTask_Exited(object sender, EventArgs e)
{
Process p = (Process)sender;
TimeSpan duration = p.ExitTime - p.StartTime;
bool success = p.ExitCode == 0;
}

How to raise an event in C# - Best Approach

I am writing a Windows Form application. It has a thread to perform some operation and when the operation found something it has to notify the main form to change a control.
Currently the notification uses the C# event hadling described in the following MSDN page:
http://msdn.microsoft.com/en-us/library/wkzf914z(VS.71).aspx
But I am not sure about the delegate. Since in the situation I described above the thread invokes the delegate. Is this a thread safe approach to raise the event?
Is it better to implement Windows Messages (SendMessage) in C# and then implement the message handler in the WindowProc.
Unless you need very fine control over the threading, you can probably use BackgroundWorker instead. It handles all of the cross-thread communication for you. You basically put your background code in its DoWork event handler and then pass data back to the UI thread via its ProgressChanged and RunWorkerCompleted events. The link above has a complete example of how to use it.
But in general, simply adding event handlers and raising events is thread-safe as long as you follow some basic guidelines. However, the event handler will be called on the same thread as the code that raises the event. The event handling code may not be expecting to be called on a background thread so that's where BackgroundWorker comes in handy.
The following is a very basic skeleton of a class that raises an event in a thread-safe way. Whether the code that handles the event is thread-safe is another matter entirely.
class MyClass {
public event EventHandler SomethingHappened;
protected virtual void OnSomethingHappened(EventArgs e) {
EventHandler handler = SomethingHappened;
if (handler != null) {
handler(this, e);
}
}
public void DoSomething() {
OnSomethingHappened(EventArgs.Empty);
}
}
Try to use InvokeRequired / Invoke on UI controls. It's better to avoid raw windows message queuing.
The delegate approach isn't all that bad, but the problem is that the event invokes the event handlers in the other thread. That foxes your UI update, which needs to be done in the main thread. So you can use InvokeRequired appropriately in the event handler.
void OnStatusMessage(string s)
{
// might be coming from a different thread
if (txtStatus.InvokeRequired)
{
this.BeginInvoke(new MethodInvoker(delegate()
{
OnStatusMessage(s);
}));
}
else
{
StatusBox.Text += s + "\r\n";
StatusBox.SelectionStart = txtStatus.TextLength;
StatusBox.ScrollToCaret();
}
}
This may not be required when using BackgroundWorker as Josh mentioned. But it's useful if you're considering ThreadPool and WaitCallBack(*) to manage threads.
An issue with using Windows messages is that you have to know which window to send messages to, and multiple subscribers is more painful. (For events you just have to += another handler)
I amn't able to post a hyperlink for WaitCallBack because I don't have multi-link pedigree yet.

In .NET, what thread will Events be handled in?

I have attempted to implement a producer/consumer pattern in c#. I have a consumer thread that monitors a shared queue, and a producer thread that places items onto the shared queue. The producer thread is subscribed to receive data...that is, it has an event handler, and just sits around and waits for an OnData event to fire (the data is being sent from a 3rd party api). When it gets the data, it sticks it on the queue so the consumer can handle it.
When the OnData event does fire in the producer, I had expected it to be handled by my producer thread. But that doesn't seem to be what is happening. The OnData event seems as if it's being handled on a new thread instead! Is this how .net always works...events are handled on their own thread? Can I control what thread will handle events when they're raised? What if hundreds of events are raised near-simultaneously...would each have its own thread?
After re-reading the question, I think I understand the problem now. You've basically got something like this:
class Producer
{
public Producer(ExternalSource src)
{
src.OnData += externalSource_OnData;
}
private void externalSource_OnData(object sender, ExternalSourceDataEventArgs e)
{
// put e.Data onto the queue
}
}
And then you've got a consumer thread that pulls stuff off that queue. The problem is that the OnData event is fired by your ExternalSource object - on whatever thread it happens to be running on.
C# events are basically just an easy-to-use collection of delegates and "firing" an event just causes the runtime to loop through all of the delegates and fire them one at a time.
So your OnData event handler is getting called on whatever thread the ExternalSource is running on.
Unless you do the marshaling yourself, an event will execute on whatever thread is invoking it; there's nothing special about the way events are invoked, and your producer thread doesn't have an event handler, your producer thread simply said "hey, when you fire this event, call this function". There's nothing in there that causes the event execution to occur on the attaching thread, nor on its own thread (unless you were to use BeginInvoke rather than invoking the event's delegate normally, but this will just execute it on the ThreadPool).
Raising an event with Invoke is the same as calling a method - it gets executed in the same thread you raised it.
Raising an event with BeginInvoke uses ThreadPool. Here are some minor details
you have to use autoresetevent handlers for this problem.....in autoresetevent when producer produses it set the signal then consumer reset its signal and consume.. after consuming consume set signal then only producer produced...
AutoResetEvent pro = new AutoResetEvent(false);
AutoResetEvent con = new AutoResetEvent(true);
public void produser()
{
while(true)
{
con.WaitOne();
pro.Set();
}
}
public void consumer()
{
while (true)
{
pro.WaitOne();
.................****
con.Set();
}
}
private void button1_Click(object sender, EventArgs e)
{
Thread th1 = new Thread(produser);
th1.Start();
Thread th2 = new Thread(consumer);
th2.Start();
}

Categories

Resources