[asio][coroutine] Intentional synchronization of a single coroutine

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

[asio][coroutine] Intentional synchronization of a single coroutine

Boost - Dev mailing list
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());
    }
}

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [asio][coroutine] Intentional synchronization of a single coroutine

Boost - Dev mailing list
On 8/9/19 9:12 PM, Jared McIntyre via Boost wrote:

> 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).

This sounds like a job for Boost.Fiber and its Boost.Asio integration:

 
https://www.boost.org/libs/fiber/doc/html/fiber/callbacks/then_there_s____boost_asio__.html

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [asio][coroutine] Intentional synchronization of a single coroutine

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Em sex, 9 de ago de 2019 às 16:12, Jared McIntyre via Boost <
[hidden email]> escreveu:

> 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).
>

Take a look at this project: https://github.com/blinktrade/iofiber

It should solve your needs.

You could... like:

spawn(ioservice, [](fiber::this_fiber this_fiber) {
    spawn(this_fiber, std::bind(&bottleneck, 3s, _1))
        .join(this_fiber);
    spawn(this_fiber, std::bind(&bottleneck, 2s, _1))
        .join(this_fiber);
    spawn(this_fiber, std::bind(&bottleneck, 1s, _1))
        .join(this_fiber);
    spawn(this_fiber, std::bind(&bottleneck, 0s, _1))
        .join(this_fiber);
})
.detach();

With IOFiber, spawn() returns a fiber handle that you can use to join() the
fiber. The handle is moveable and then you can pass it around. Check the
documentation.

--
Vinícius dos Santos Oliveira
https://vinipsmaker.github.io/

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [asio][coroutine] Intentional synchronization of a single coroutine

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
Em sex, 9 de ago de 2019 às 18:33, Bjorn Reese via Boost <
[hidden email]> escreveu:

> This sounds like a job for Boost.Fiber and its Boost.Asio integration:
>
>
>
> https://www.boost.org/libs/fiber/doc/html/fiber/callbacks/then_there_s____boost_asio__.html
>

Oliver has a few comments regarding integration between Boost.Asio and
Boost.Fiber (for those interested):
https://github.com/boostorg/fiber/issues/102


--
Vinícius dos Santos Oliveira
https://vinipsmaker.github.io/

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost
Reply | Threaded
Open this post in threaded view
|

Re: [asio][coroutine] Intentional synchronization of a single coroutine

Boost - Dev mailing list
In reply to this post by Boost - Dev mailing list
On 8/10/19 4:27 AM, Vinícius dos Santos Oliveira via Boost wrote:

> With IOFiber, spawn() returns a fiber handle that you can use to join() the
> fiber. The handle is moveable and then you can pass it around. Check the
> documentation.

That is an elegant solution.

_______________________________________________
Unsubscribe & other changes: http://lists.boost.org/mailman/listinfo.cgi/boost