From: Hurd, Matthew (hurdm_at_[hidden])
Date: 2004-02-16 22:31:17
> On Behalf Of scott
> Subject: RE: [boost] Re: Re: Future of threads (III)
> > On Behalf Of Hurd, Matthew
> > AO's should either have a queue for work or hook into a
> > queue. They are
> > a bit like a worker pool with one worker ;-)
> > Another idiom is a future value, where you ask for a value and don't
> > block until you "read" the value. ACE also has an implementation of
> > this. You can think of it as a bit like overlapped I/O.
> Yes. This was also in the ActiveObject pattern. It was on the "client-
> side", i.e. available to the thread that submits Method Requests as a
> means to acquire the results.
> While I understand its place in the ActiveObject pattern I would hope
> that if a boost::active_object came into existence, there would be a
> single (i.e. not _simple_) mechanism by which data passed from one
> to the other, with an associated notification. In a behavioural sense,
> the future mechanism wouldnt be appropriate for this.
I'd agree here in principle to keep this asynchronous and have the
equivalent of message passing with a function call with a void return
The future_value is an elegant idiom for providing a C++ RPC / LPC
equivalent. The whole store and forward expectation issue would suit
this style as it just looks like a normal function or method call.
> This way of thinking does require that all threads are active_objects
> which may be too aggressive <shrug>. A small sample of empirical data
> says its fine.
It works a treat for a lot of things. Especially suited to workflows of
things that you want to dynamically configure.
Threading is a big overhead though. Consider these numbers:
Safe increment (Athlon 2800+) (P4 3.2GHz)
Interlocked primitive 11 ns 53 ns
Critical section 138 ns 411 ns
A bit slower than a single machine instruction. If I make a size_t
volatile and time 100 increments in a row I get 3.8ns per increment on
the P4 above, more then ten times slower than an interlocked increment.
And it doesn't end there, the cache effects also add considerably. So
in my mind, the active object pattern is good for configurability and
where the work of the object is chunky enough to where the cost of the
context switches and cache effects.
In terms of work pools, this context overhead also led to the idea of a
leader-follower pattern where you try and use the same worker if
This is also why we have seen the argument for a shared_ptr with
multi-thread safety as a policy. On a Pentium 4 you are typically
paying around ten times the cost of a normal increment for the privilege
of thread safety.
> > I also advocate a different architectural neutral style where you
> > have things at look like function calls that can be:
> > 1. a function call
> > 2. a call to queue work pool or active object
> > 3. an IPC mechanism for same machine transfer, e.g.
> > shared memory
> > 4. a network mechanism, TCP, UDP, TIB or something, for
> Understand the reasons you ask for 1...4 but would like to add some
> other thoughts to see what you think.
> An ActiveObject servant contains code. That code is implementation
> of behaviour and its what (I believe) we tacitly want when we all
> say that "thread-inherited-classes" or "active objects" are a nice
> manner in which to deal with threads.
> (note: more accurately the pattern says that thread==scheduler and
> a scheduler executes servant code. but i think we can skip this
> If the code is in the servant, what do 1 and 2 mean? My best matching
> of your thinking with the servant-based thinking would be that somehow
> the "client" can submit something into the "worker pool" that
> a function that is in the servant. It would be nice if this "work
> submission" could carry some arguments for presentation to the
I think I understand what you're saying, but I'm not sure. Are you
thinking about how the marshalling is done?
> A detail that I am labouring is the separation of "calling" (would
> much rather that this was "sending") and execution. Our active object
> has no synchronous i/f with methods for us to call; it is simply a
> "work pool" that we add to. As soon as we make a sync i/f available
> then we go down that road that leads to servant code in the client.
> I suggest that notions of "function call" should be exorcised from
> discussions that are targeting active objects. That type of thinking
> is perfectly valid in some other thread (oops) but can scuttle work
> targeting active objects; the behaviour (i.e. the code) is inherently
> in the object.
Not sure I agree. Think of it the small talk way. A message is a
You could have your active object providing a function call that puts a
message on to its internal queue and returns. This way you could
perhaps specialise by policy whether or not it had its own thread of
control and make your architecture a lot more flexible similar to the
relationship of 1. and 2. above.
> a client can only submit "worker orders" or "Method Requests" or
> jobs or messages or signals.
> I hope there is enough there to make a case :-)
You certainly have a case. The nirvana I'm looking for is a policy
approach to reconfiguring architecture so I can make late decisions
about single, multi-thread, multi-process, distributed design. I think
your active object can gel with this as I think you can consider
parallels to the numbering above:
1. method call
2. method call that generates message to active object thread of
control and returns
3. method call -> lightweight message on the same box or LRPC
4. method call -> external system message (tcp, udp, tib, etc) or
> > If it can be enabled by a policy driven approach then you can
> > change the
> > architecture of your application by simply changing policies.
> > I think David Abraham's named parameters could help greatly with
> > approach, along with the serialization lib for marshalling support.
> > This should provide a solid basis for this. I've also thought that
> > perhaps boost::signals might be the correct approach to take for
> > but I'm unsure.
> > To support this approach you also need mutex aspects that are also
> > policy driven. I am preparing to submit such locking that
> > builds on the
> > existing mutexes and locks.
> <phew> That is quite a scope. But yes, I can see that ultimately
> it should cover all these dimensions. Maybe a phasing?
Yep, I think the locking and mutex stuff needs to be cleaned up or
wrapped to suit a policy approach.
Need atomic op support too.
Next step is a thread safe queue. Perhaps two, one with priority and a
normal one. I've got these I can submit but they're defective in terms
of exception safety.
Next step is a way having a policy based interface approach to make
calling a function result in the calling of a function or marshalling
the parameters and calling something else... This is the bit where I'm
not sure how best to approach it.
Then it is a latter of adding transports to enrich the approach.
Good thinking there Scott.
Susquehanna Pacific P/L
IMPORTANT: The information contained in this email and/or its attachments is confidential. If you are not the intended recipient, please notify the sender immediately by reply and immediately delete this message and all its attachments. Any review, use, reproduction, disclosure or dissemination of this message or any attachment by an unintended recipient is strictly prohibited. Neither this message nor any attachment is intended as or should be construed as an offer, solicitation or recommendation to buy or sell any security or other financial instrument. Neither the sender, his or her employer nor any of their respective affiliates makes any warranties as to the completeness or accuracy of any of the information contained herein or that this message or any of its attachments is free of viruses.
Boost list run by bdawes at acm.org, david.abrahams at rcn.com, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk