Is it safe to use spawn directly in an asio stackf

2020-06-22 09:26发布

问题:

When I use spawn to start a new stackfull coroutine in a coroutine, valgrind says a lot of using uninitialised value(valgrind output).

Then I use io_service.post to invoke a handler,and start a new stackfull coroutine in it, every thing seems fine.

I have searched and read some documents, but can't find something about how to create a new stackfull coroutine safely in a stackfull coroutine.

Here is the code:

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

using namespace std;

int main()
{
    auto use_post = false;
    boost::asio::io_service io_service;
    boost::asio::spawn(io_service,
                       [&io_service, &use_post](boost::asio::yield_context yield){
        if(use_post){
            io_service.post([&io_service]{
                boost::asio::spawn(io_service, [&io_service](boost::asio::yield_context yield){
                    boost::asio::system_timer timer(io_service);
                    timer.expires_from_now(std::chrono::seconds(1));
                    timer.async_wait(yield);
                    cout << "Sleep 1 second" << endl;
                });
            });
        }
        else{
            boost::asio::spawn(io_service, [&io_service](boost::asio::yield_context yield){
                boost::asio::system_timer timer(io_service);
                timer.expires_from_now(std::chrono::seconds(1));
                timer.async_wait(yield);
                cout << "Sleep 1 second" << endl;
            });
        }
        boost::asio::system_timer timer(io_service);
        timer.expires_from_now(std::chrono::seconds(2));
        timer.async_wait(yield);
        cout << "Sleep 2 seconds" << endl;
    });
    io_service.run();
    return 0;
}

set true to use_post variable, new stackfull coroutine will be started by post + spawn.

Maybe I don't read the documents carefully, i can't find any thing usefull in Boost.Asio C++ Network Programming, N4045 and boost asio document.

回答1:

It is safe.

Boost.Asio's first-class support for Boost.Coroutine is a thin facade with two notable behaviors:

  • A coroutine and handlers which resume it use a strand for their execution context. This guarantees the coroutine will not be resumed before it has yielded.
  • Boost.Asio prevents a coroutine from staying indefinitely suspended if it detects that there are no handlers available to resume it. When this occurs, Boost.Asio will destroy the coroutine, causing the suspended stack to unwind. See this answer for more details.

In the example code above, the spawn(io_service&) overload causes the resulting coroutine to have its own strand. As a result, if multiple threads are running the io_service, each of the coroutines may run in parallel, but are not guaranteed to do so. On the other hand, if one uses the spawn(yield_context) overload, the new coroutine will have the same execution context (i.e strand) as the calling coroutine, preventing parallel execution.