|
Boost : |
Subject: Re: [boost] Asynchronous library now in Boost Library Incubator
From: Christophe Henry (christophe.j.henry_at_[hidden])
Date: 2016-12-06 16:14:31
<snip>
> Just out of curiosity, I implemented your example just with executors and
> future::then:
> https://gist.github.com/sithhell/42eec1e183df206556086cfbf20918ac
Oh we are back to HPX...
Well, if it's out of curiosity... I can't promise to give a correct
answer due to my little knowledge of HPX. Please excuse my possibly
incorrect interpretations.
> Granted, it doesn't bind the lifetime of the manager to the object, but that
> should be a trivial, for example with an intrusive pointer instead of raw this
> in the continuations. And it misses the proxy object which
> could be implemented to hide this lifetime tracking in a similar way that
> boost.async, although, the destructor of the executor waits until all threads
> have been processed (implicitly keeping the object alive long enough). Other
> than that, it has the same race freedom guarantees, due to only ever
> manipulating the object on a single thread of execution. It only blocks on the
> future returned from start(). The location on where to execute the callback/
> continuation is fixed. The "thread world" is defined by the executor, which is a
> very generic and powerful abstraction and properly aligned with the current
> development in the C++ Standards Committee. The layered example can be done in
> a similar fashion, each object containing its own executor.
> What do you think?
From what I understand, I don't think both examples are equivalent (yet):
- the lifetime issues are not visible in this example. There is a single
object and it is living in main's thread, which removes quite some salt.
It has no interaction whatsoever with other threads or objects. My
example shows interaction with the main thread.
- as you wrote, there is no proxy. If the manager object lived in
another thread than main, it would be non-trivial to avoid races. Calls
to members would be a race. Destructor would also become an issue.
A key point of my example is that the object is now complete and
reusable in a different thread context. I could extend the example at
will with more threads and continue to have no thread issue. As it is,
your manager object is still thread-unsafe if used in another context.
Of course it can be implemented, it is already done, in servant_proxy.
- how many threads are there? I'm unsure if one or two. In my example,
there are 3 (main, servant thread, threadpool), though I'm sure your
example can be extended to have the same number.
It looks like task and callback are executed in the same thread
(executor). Correct? My example executed the long tasks in the
threadpool. I'm quite sure your example can also be extended to do the same.
I think it's great. We are just scratching the surface but we are coming
to the interesting stuff.
In the example, the manager object is created on the stack, is alone
with no interaction with other objects or libraries, even less with
external threads.
But if we imagine lots of thread worlds, each with hundreds of servants
and proxies, things start becoming interesting. One simply cannot define
all of the application objects in main and life issues appear quickly.
I'll try to think of a realistic example showing such a thing.
You might want to have a look at the next example in the doc, the
layers, which makes things even more interesting by introducing safe
callbacks, which can be called from any thread (asynchronous thread
worlds or whatever thread the application has). I hope it will then be
clear that a single object on a stack is not a general solution and that
an object living and being accessed in a clearly defined thread with no
outside possibility to use it incorrectly is a better one.
Sorry, it looks like generating the doc broke the links.
Here the link to the named examples:
Regards,
Christophe
Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk