Streams, ownership and observability

Dec 14, 2006 21:44

Something that always bothered me while programming with WvStreams was how everything had to be a stream. Well, I actually, I had demonstrated how it could be avoided, but it was a rather contrived idea where there was a free-floating object, not clearly owned by anyone, but which registered with the close callback of a stream, where it then committed "suicide". Sort of worked, but explaining it to people was a pain, and there was much opportunity to get it wrong...

Hand in hand with this, I was thinking about a next-generation event-driven API, where the lowest level would use XPLC interfaces, so that the various participants could be of different origins and not necessarily have to link with the exact same libraries. The event dispatcher would take an interface pointer to call back into, and I was contemplating whether this should be a strong or a weak reference.

In the WvStreams style, it would be a strong reference, making the fact that an object is waiting for an event extend its lifetime. This can make things rapidly confusing, since this would require an out-of-band method to tell the stream to un-register itself from the event dispatcher, which would then cause it to die. Correction, it could be a strong reference, but could be a weak one just as well, where un-registering might or might not cause it to die. That's a whole lot more maybes than what I'm comfortable with when it comes to a maintainable ownership model (I can usually make sense of what I wrote, but people coming in my code afterward have to read up a lot of code to know what's going on for sure). But having a global object that's closely involved (the event dispatcher) to deal with the ownership is handy...

Another thing that was handy was how the WvIStreamList could help with identifying streams, and help debug problems with them (largely thanks to the work of pzion!). Having as much information about the objects involved is very useful in a complex server, since any number of things could be happening concurrently, and just knowing that it was a crash in the method WvStream::post_select isn't exactly useful, when it is part of just about every object in the system! So, another important attribute is observability and debuggability.

So I had an idea that I think could be an improvement on all accounts. Registering for events is a weak reference, always, but I add a separate "task" concept. Tasks provide a context for a certain processing, and they are a bit like processes in a Unix system, which do not directly have owners other than themselves (they can exit) and the kernel (they can be killed). They provide the strong ownership for the streams that the event dispatcher wouldn't assume anymore. When creating then, they would be able to identify themselves better, being able to list them, and parentage information. Concretely, in C++ terms, the Task class would be what people would derive all the time, instead of deriving WvStreams to make decidedly non-stream things just in order to get the lifetime managed properly. This is similar to my contrived hack, but with observability and a uniform lifetime model thrown in, which was sorely missing.

As a side-note, I think TR1's shared_ptr, weak_ptr and friends are pretty damned sweet. I'm aware this might come off as pretty radical, but I think we should get on with the times and get rid of most raw pointers in C++ programming.

I'll have to go and do some prototyping of this to see if I'm delusional again.

cpp, tech

Previous post Next post
Up