April 03, 2008
>> When doing embedded controller work, I used a very similar design for passing data up a TCP/IP stack to the app.  During profiling, I found that a significant amount of the CPU time was being spent in the dispatching of i/o events that just got ignored.  By changing the event handlers to say "thanks, but don't send me any more", I was able to save something like 10-15% CPU time.  (Profiling never shows you what you expect.  :-)
> 
> Interesting. I suppose in GUI design, one widget will always or never want to handle a responsibility. You could return an enum value PassOn, Stop, or SendNoMore. And then the library would want to determine which to return, and just accept a void delegate for the event handler.

I tried using it under Windows once, setting callback functions for various events.  It worked okay, but didn't allow for multiple watchers.  I think for the GUI it's better to use a signals & slots model.  It provides more flexibility.  I/O, on the other hand, usually has just one chain of objects.


>> In the case of a C++ program in a proper operating system, think of the "write" event from a select call.  If you leave it active but write nothing, you'll just get the event again and again and again.  You'll spin CPU instead of letting the OS notify you.
>>
>> There are other solutions, of course.  In my C++ library, you had to make a call to clear the "write callback" when you didn't want such events.  That would work it's way down the stack of objects until it cleared the respective bit from the "write" fd_set.  This ended up being somewhat clumsy to implement though because objects are responsible for themselves, it was never anything the library user had to worry about.
> 
> A bit easier to manage if you're using singletons, though that doesn't work in many cases. Or you could pass in whatever created the event along with the event data.

I always include the generator object in the call.  That allows a single object to accept from multiple sources, like an HTTPserver with multiple open connections.


>> Instead, I thought I'd take a simpler approach of just requesting "all or nothing" and letting the system take care of turning off those that aren't wanted when they occurred.
>>
>> I figured it would also be beneficial to minimize the number of potential loops in the object stack.  If calling "DisableEvent" from within an event handler, you run the risk of that method generating some different event and calling back up the stack yet again.  By returning the status, then any other events generated aren't a loop.
> 
> I've had some issues with that in the past. I don't think there is a simple solution. Though for GUI stuff, you could often use data binding for simple cases.
> 
>> In the presence of a proper event queue, loops never happens because the next item on the queue doesn't get processed until the previous one completes.  Using callbacks, however, this is not the case as every "event" is always processed directly and immediately.
> 
> What prevents you from adding to the queue an event that will cause this event to be added to the queue again?

Nothing, but there are differences.  Any given event gets fully processed before the next one.  With callbacks, you can get one within another.  In the case of an event adding itself, you effectively have an infinite loop.  In the case of a callback calling itself, you have a stack overflow.

-- Brian
1 2
Next ›   Last »