Boost logo

Boost :

From: Jared McIntyre (jmcintyre_at_[hidden])
Date: 2019-08-09 19:12:27


Within a large asynchronous project, I have a coroutine that needs to
synchronize with other calls to that coroutine. This is a very simplified
(and somewhat silly) example:

#include <iostream>
#include <cstdlib>
#include <chrono>
#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>

using namespace std;
using namespace std::chrono;
using namespace std::placeholders;
using namespace boost::asio;
using namespace std::chrono_literals;

io_service ioservice;

void bottleneck(seconds duration, yield_context yield)
{
    steady_timer delay_timer(ioservice);
    delay_timer.expires_after(duration);
    delay_timer.async_wait(yield);

    std::cout << duration.count() << " ";
}

int main()
{
    spawn(ioservice, std::bind(&bottleneck, 3s, _1));
    spawn(ioservice, std::bind(&bottleneck, 2s, _1));
    spawn(ioservice, std::bind(&bottleneck, 1s, _1));
    spawn(ioservice, std::bind(&bottleneck, 0s, _1));
    ioservice.run();
}

The output is, of course, 0 1 2 3 because the timer effectively acts to
re-order the calls. What I need is a way for each call to bottleneck() to
fully complete before the next one starts, and each call occurs in the
order they were called. This would make the output 3 2 1 0. I also want to
allow other asynchronous routines on the io_service to run when the
coroutine is yielding (so no cheating and turning the delay timer into a
sleep).

I've tried to think through something like the following. But I have no
idea how to make it work.

yield_context_queue bottleneck_queue;

void bottleneck(seconds duration, yield_context yield)
{
    bool yield_time = !bottleneck_queue.empty()
    bottleneck_queue.push_back(yield);

    if( yield_time )
    {
         yield_back;
    }

    steady_timer delay_timer(ioservice);
    delay_timer.expires_after(duration);
    delay_timer.async_wait(yield);

    std::cout << duration.count() << " ";

    bottleneck_queue.pop();

    if( false == bottleneck_queue.empty() )
    {
          ioservice.post(bottleneck_queue.peak());
    }
}


Boost list run by bdawes at acm.org, gregod at cs.rpi.edu, cpdaniel at pacbell.net, john at johnmaddock.co.uk