6 Dec
2016
6 Dec
'16
9:43 p.m.
Am 06.12.2016 10:14 nachm. schrieb "Christophe Henry" < christophe.j.henry@gmail.com>: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. This is not really HPX specific. You can do the same with Boost.Thread, the concurrency TS, executors, coroutines. All basically speaking the same language. 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. This does too. - 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. What I was trying to say was: the concept you introduce is completely orthogonal: you can easily implemented it on top of such things. If I could reimplement everything you did on an afternoon, that would be great ;) Regarding the threads: yes, i was not really aware of your three threads active. That shouldn't be important. And yes, it can be extended. What's important are the semantics, and I'm confused again... In a single thread world can two member functions be called concurrently on an object living in that world? It seems it can, the servant and threadpool? I'm sorry, the more I think about it, the more confusing it gets. It would be great if we'd speak the same language as well, why not call your thread worlds executors and open a whole new world of possibilities ;) 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. Don't get me wrong, I'm not really trying to say that libraries like hpx, or boost.thread or folly or ppl solved your problem. I was trying to demonstrate that futures, async and friends are not your enemies, on the contrary. Regarding the layered example, I'm still trying to understand the semantics of your different APIs. There are a lot of things doing the same from a different perspective (proxy, servant, scheduler). Sorry, it looks like generating the doc broke the links. Here the link to the named examples: https://htmlpreview.github.io/?https://github.com/henry-ch/a synchronous/blob/master/libs/asynchronous/doc/asynchronous.html#d0e6434 Regards, Christophe _______________________________________________ Unsubscribe & other changes: http://lists.boost.org/mailman /listinfo.cgi/boost