--
You received this message because you are subscribed to the Google Groups "Cap'n Proto" group.
To unsubscribe from this group and stop receiving emails from it, send an email to capnproto+...@googlegroups.com.
Visit this group at https://groups.google.com/group/capnproto.
Hi Sandeep,I haven't used this Boost library so I could be missing things, but here are my thoughts:First, note that Boost's futures are meant to cross threads whereas KJ's promise framework is not thread-aware. You'll need to make sure that boost's .then() calls the callback in the correct thread.
Regarding exceptions, your approach below is one possibility: basically, the promise resolves when the boost future is ready, but it's still up to the caller to call .get() which may throw an exception. If you'd rather have a boost future exception propagate directly into a KJ promise exception, you could do it by actually calling .get() inside the boost future callback:bf_.then([this] (BF samef) {promiseFulfiller_.rejectIfThrows([&]() {promiseFulfiller_.fulfill(samef.get());});
});Above, if get() throws, it'll be equivalent to calling promiseFulfiller_.reject().In this approach, boost::future<T> would translate into kj::Promise<T>, *not* kj::Promise<boost::future<T>> -- this seems like an improvement.
Regarding the adapter's destructor: It should "cancel" the operation somehow, such that the callback passed to future.then() is never called. Boost futures mighht not support cancellation, though. You could work around this by documenting your BoostPromiseAdapter to say that users must not cancel the adapted promise (i.e. they must not destroy it until it completes). Otherwise, you might want to try a completely different approach: use kj::newPromiseFulfillerPair<T>() instead of PromiseAdapter. This gives you a promise/fulfiller pair which are analogous to Boost's future/promise pair (it is unfortunate that Boost uses the word "promise" differently from everyone else, ugh). You can then arrange to fulfill the KJ fulfiller when the Boost future is done, while returning the KJ promise separately. Destroying the KJ promise will simply cause the fulfiller to be ignored.
Regarding shared_future, I don't think it changes anything in particular. Did you have a specific question there?
On Mon, Jan 11, 2016 at 9:50 AM, Kenton Varda <ken...@sandstorm.io> wrote:Hi Sandeep,I haven't used this Boost library so I could be missing things, but here are my thoughts:First, note that Boost's futures are meant to cross threads whereas KJ's promise framework is not thread-aware. You'll need to make sure that boost's .then() calls the callback in the correct thread.You are right. I have to use boost::launch::deferred in my use-case.
Maybe I am missing something in your alternate approach, because the comment in kj/async.h says
"// Although this function is easier to use than `newAdaptedPromise()`, it has the serious drawback
// that there is no way to handle cancellation (i.e. detect when the Promise is discarded)."
https://github.com/sandstorm-io/capnproto/blob/master/c%2B%2B/src/kj/async.h#L473
Is this comment outdated ?
OTOH, the AdapterPromiseNode::fulfill() checks the waiting flag but I can't find who is setting it
On Mon, Jan 11, 2016 at 1:16 AM, Sandeep Joshi <sanj...@gmail.com> wrote:On Mon, Jan 11, 2016 at 9:50 AM, Kenton Varda <ken...@sandstorm.io> wrote:Hi Sandeep,I haven't used this Boost library so I could be missing things, but here are my thoughts:First, note that Boost's futures are meant to cross threads whereas KJ's promise framework is not thread-aware. You'll need to make sure that boost's .then() calls the callback in the correct thread.You are right. I have to use boost::launch::deferred in my use-case.Hmm, but this seems like it would require integrating KJ's event loop with Boost's event loop. Have you written such an integration?
On Monday, January 11, 2016 at 11:38:01 PM UTC+5:30, Kenton Varda wrote:On Mon, Jan 11, 2016 at 1:16 AM, Sandeep Joshi <sanj...@gmail.com> wrote:On Mon, Jan 11, 2016 at 9:50 AM, Kenton Varda <ken...@sandstorm.io> wrote:Hi Sandeep,I haven't used this Boost library so I could be missing things, but here are my thoughts:First, note that Boost's futures are meant to cross threads whereas KJ's promise framework is not thread-aware. You'll need to make sure that boost's .then() calls the callback in the correct thread.You are right. I have to use boost::launch::deferred in my use-case.Hmm, but this seems like it would require integrating KJ's event loop with Boost's event loop. Have you written such an integration?
Nope. When you specify a deferred launch in Boost, the continuation gets executed in the current thread when future.get() is called.
In order to integrate such functionality with the kj event loop, I would have to capture all the outstanding boost promises in the current thread and feed it into my implementation of a kj::EventPort. Is that more or less correct ? I have seen the code you posted earlier for node-capnp
https://github.com/kentonv/node-capnp/blob/master/src/node-capnp/capnp.cc
Would it easier to put a mutex-type wrapper on KJ promises to make them thread-safe ?
Nope. When you specify a deferred launch in Boost, the continuation gets executed in the current thread when future.get() is called.
In order to integrate such functionality with the kj event loop, I would have to capture all the outstanding boost promises in the current thread and feed it into my implementation of a kj::EventPort. Is that more or less correct ? I have seen the code you posted earlier for node-capnp
https://github.com/kentonv/node-capnp/blob/master/src/node-capnp/capnp.cc
Would it easier to put a mutex-type wrapper on KJ promises to make them thread-safe ?
Alternately, I could write to a pipe in the boost continuation (in any thread) and let the corresponding kj::evalLater() wait on the read end.
The promise returned from evalLater() can be fed to the ioContext.
Would this work ?
If yes, is there a way I can avoid creating a pipe for every conversion from a boost::promise to kj::Promise ?
-Kenton
I need to pick your brain a little more ;-)
I am able to connect the boost::future ==> unix pipe ==> kj::Promise, but I am having difficulty demultiplexing multiple promises whose values are being written to the same pipe, primarily because I don't know how to tie the kj::Promise returned from kj::evalLater() to the actual promise I want to wake up.
Do I tie them with a PromiseFulfillerPair or another continuation ?
Can the kj::event loop repeatedly check in non-blocking fashion for the same promises until they are ready ?
Can I call kj::evalLater() within the lambda passed to evalLater() to re-register the function if there are multiple waiting promises ?
-Kenton
On Sat, Jan 23, 2016 at 7:25 AM, Kenton Varda <ken...@sandstorm.io> wrote:On Tue, Jan 19, 2016 at 4:19 AM, Sandeep Joshi <sanj...@gmail.com> wrote:I need to pick your brain a little more ;-)
I am able to connect the boost::future ==> unix pipe ==> kj::Promise, but I am having difficulty demultiplexing multiple promises whose values are being written to the same pipe, primarily because I don't know how to tie the kj::Promise returned from kj::evalLater() to the actual promise I want to wake up.
Do I tie them with a PromiseFulfillerPair or another continuation ?Yes, you'll probably want to use PromiseFulfillerPairs. I imagine you'd have something like a map<int, kj::Own<kj::PromiseFulfiller<T>>> assigning IDs to each fulfiller, and you'd write the ID through the pipe.Can the kj::event loop repeatedly check in non-blocking fashion for the same promises until they are ready ?Sorry, I don't understand what you mean here.Can I call kj::evalLater() within the lambda passed to evalLater() to re-register the function if there are multiple waiting promises ?Again not sure what you're suggesting here, but I would say that a polling busy loop is definitely not what you want.
I guess I am able to articulate the solution but unable to actualize it, given the massively useful but equally intricate framework you have built ;-)I want to do promise pipelining - return many promises (RemotePromise) from the server to the client and let it retrieve the results as and when they are ready. But I don't understand how to bind the promise returned by kj::evalLater() with the promise which has been returned to the client. The evalLater() is needed to read the pipe, but thats not the promise which will be returned to the client. Thats the crux of the problem.