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.
Related
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?
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);
}
}
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.
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();
}
I'm writing a wrapper class around a TcpClient which raises an event when data arrives. I'm using BeginRead and EndRead, but when the parent form handles the event, it's not running on the UI thread. I do I need to use delegates and pass the context into the callback? I thought that callbacks were a way to avoid this...
void ReadCallback(IAsyncResult ar)
{
int length = _tcpClient.GetStream().EndRead(ar);
_stringBuilder.Append(ByteArrayToString(_buffer, length));
BeginRead();
OnStringArrival(EventArgs.Empty);
}
The parent form should be using the Invoke method on its controls in the event handler to ensure it's on the right thread; it's not the job of your background process to conform to what the UI needs. This msdn page has an example.