views:

94

answers:

6

Hello,

I'm currently designing an assembly that will be used by third parties. One of the classes has a long process of TCP connections and it informs about its process using events. For example

''# Do stuff that takes some time
RaiseEvent CompletedFirstPartEvent()
''# Do stuff that takes some time
RaiseEvent CompletedSecondPartEvent()
''# Do stuff that takes some time
RaiseEvent CompletedSecondPartEvent()

What I've seen if that if the handler of one of those events takes too long (or even worse, it blocks) I can have timeouts and it's hard for the developer to see that one class is not working fine because his handler is taking too long.

I was going to fire the events in a new Thread to avoid this issue but this looks strange to me because I've never seen something like that, what I've seen until now is the developer spawning a new Thread if his handler was going to be timeconsuming. So the question is:

What would you do? Create a new thread or force the user to create his own thread? (Or is -there a better approach that I don't know?)

Thanks in advance.

+1  A: 

why don't you use backgroundworker?

Benny
Because usually is the programmer that consumes the events the one that is responsible of running long time tasks on other threads and looks strange to me throw events using a background worker.But if I let the user to decide and he takes the wrong option will be hard for him to know what is happening because one system will be having timeouts just because he has an event handler that takes a bit too long to execute. Is it clear enough?
SoMoS
+2  A: 

We ran into the same thing when building WebSync - how do you allow for long-running processes in user code without sacrificing your app?

What we decided to do was to give the user the option (our setup is not identical to yours, but the premise should work). Basically, allow the user to tell you whether or not to spin off the events on a new thread.

This way, if the developer knows they have fast operations, they can avoid the overhead of new threads for every event, and can also be assured that the events will run in a specific order (otherwise, they could easily end up with threading issues in their own code due to all the events firing on distinct threads), but if they have processes that are potentially blocking, they can specify that they want the extra overhead, and can deal with any potential threading issues themselves.

In this scenario, you just have to then watch a flag, and decide as appropriate to fire off the events synchronously or on a thread. Best of both worlds (although a little more complicated on your end).

jvenema
What I'm trying to avoid is to have users that does not know what's going on because I understand that its hard to diagnose that one connection has timeouts because an event handler takes too long to execute.Anyway you get a +1 because I didn't realize that events can be raised out of order if throwing them in new threads.
SoMoS
Edit:If you need to preserve ordering, and you want to use threads to invoke your calls into user code, your only option (that I know of) is to maintain a queue of events within your code, and instead of firing them directly, add the event to the queue. Then on completion of the event, check to see if the queue is empty, and if not, fire the next item in the queue. This could result in strangeness ass well though, depending on if there's any reliance on timing between the events.
jvenema
+2  A: 

I definitely wouldn't fire the events on their own threads. Let the consumer of the code decide the best way to handle things.

Tough to give a definitive answer without more details, but another thought would be to consider alternate approaches to events. Maybe a queue of notifications that the consumer could consume on his/her own time? Let the event be that a new item was added to the queue. That let's things be more asynchronous. The consumer could have a separate thread for processing queue messages.

Brian Frantz
I liked your way of lateral thinking. +1
SoMoS
+1  A: 

I've got a Collector class that opens a "raw" socket and collects data from the local network. Internal to the Collector class, the socket reads are done by a Receiver thread. This thread fires an InternalPacketReceived event for each packet that is read from the network. Also internal to the Collector class, I also have a Distributor thread that subscribes to the Receiver's InternalPacketReceived event. Packets received by the Distributor's handler are added to an internal packet queue. The Distributor thread is then responsible for making the packets in the queue available to subscribers of the Collector's public PacketReceived event. In this way, if the Distributor thread is stalled by a long-running handler, the Receiver continues to read packets without delay.

From the user's perspective, he's interacting with a public interface on the Collector class - Start(), Stop(), subscribe to PacketReceived event, etc. Behind the scenes, the Collector is using two threads - Receiver and Distributor - to avoid the problem introduced by long-running handlers.

I hope that's clear.

Matt Davis
I like your solution and i will implement it. Thanks.
SoMoS
+1  A: 

If the user of your assembly is consuming events and taking too long to handle them, that should be their problem to deal with, not yours. You can't bullet proof against dumb programming.

statenjason
Yes, but can be hard for them to see that putting an event handler has a side effect of doing that a communications method throws timeouts.
SoMoS
Document it and give a helpful exception message on the timeout. Also, the accepted answer sounds like a reasonable solution.
statenjason
+1  A: 

It can be a good Threadpool usage


Your "Do stuff" seems to be long with some infrequent event notifications. You want some kind of "fire and forget" notification and be sure that called delegates dont clutter you (they can take too long and/or raise exception).

  • Create a thread for each published event can be costly.

  • BackgroundWorkers are only usefull for GUI (WinForms) notification.

Why don't use Threadpool? It's cheap and isolate you from deviant behavior.

MuiBienCarlota
Because I don't think that its what people use to do when something like that happens. And because using the Threadpool the event order can be messed (the events are used only to notify about the process completion status).
SoMoS