Hello @ll,

I am in the process of transforming a sync server application to an async approach. The framework in use (not asio) instantiates and calls an object representing the call when a request comes in, allows me to do things, fill a response object and then expects me to call a finish() method which will send the response and start the next request. This is not what this question is about but more like my circumstances. All code is pseudocode please...

void rpc_work() {
   const value = do_stuff(request);
   response.fill_value(value)
   parent->finish();
}

Now some of the calls will imply calling methods, which block on some operations, waiting for external resources to respond. Obviously in an async server with only one thread, this will block everything. So I'm looking for a clever way to structure this.

My approach so far (in the prototype) is to go boost::async() for those operations. Like this:

void rpc_work() {
   // prepare work
   boost::async(launch::any, [request, response, parent]() {
         const value = do_blocking_stuff(request);
         response.fill_value(value)
         parent->finish();
   });
}

The way I understand boost::async or indeed std::async is, that normally it will just spawn a thread for the operation. The best I can hope for is a thread pool but this is not guaranteed either (on Linux x64 gcc 7.3).

So I started looking into fibers but I'm having a hard time understanding them, which is why I post here. From what I gather, what I have here is a prime use case as it matches many things the docs talk about. And yet they also suggest that the fibers are very intrusive and everything underneath do_blocking_stuff() would have to be aware of being in a fiber and yield() when appropriate. Is this correct? What would this mean?

Most if not all of the blocking operations are using boost::thread::futures in their blocking things. They would do things like...

value_t do_blocking_stuff(request) {
   boost::future<value_t> fv = retrieve_value_from_somewhere();
   fv.wait_for(timeout);
   return fv.get()
}

Now, considering I would use fibers in the server, would I have to use 'fiber futures' here to make this work? To make the blocking functions automatically 'fiber aware' and yield() when they would block? This would imply replacing the thread::futures?
And if so, how will I know when the value is there and they are ready to continue? And how will I cause this continuation? Do I have to keep track of them and somehow poll() them in a loop or something?

I am aware of the broad nature of my question but perhaps someone can chime in and give some hints that allow me to understand them better. They look like they would fit my use case perfectly but I am a bit reluctant of dragging the concept all throughout the code until I realize it won't work.

Perhaps someone can eli5 this to me ;-)

Cheers,

Stephan