Уступая в Boost.Asio Stackful сопрограммы

При использовании стековых сопрограмм Boost.Asio, как я могу «вручную» выдать, чтобы была возможность запустить другую сопрограмму или асинхронную операцию? Например, мне нужно выполнить длительные вычисления перед отправкой ответа на команду, полученную из сокета TCP:

asio::spawn(strand_, [this, self](asio::yield_context yield)
{
char data[256];
while (socket_.is_open())
{
size_t n = socket_.async_read_some(boost::asio::buffer(data),
yield);

if (startsWith(data, "computePi"))
{
while (!computationFinished)
{
computeSomeMore();
yield; // WHAT SHOULD THIS LINE BE?
}

storeResultIn(data);
boost::asio::async_write(socket_, boost::asio::buffer(data, n),
yield);
}
}
});

5

Решение

Это проще, чем вы думаете:

iosvc.post(yield);

сделает свое дело.

(iosvc заимствовано из примера кода @ sehe)

4

Другие решения

Вы можете просто позвонить poll_one() на объекте io_service.

Полный рабочий образец:

#include <boost/asio.hpp>
#include <boost/asio/spawn.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/thread.hpp>
#include <iostream>

namespace asio = boost::asio;
using boost::asio::ip::tcp;
using std::begin;
using std::end;

bool computationFinished = false;
void computeSomeMore() {
static int count = 0;
if (count++>10)
{
computationFinished = true;
std::cout << "Calculation finished\n";
} else
{
std::cout << "Calculating...\n";
boost::this_thread::sleep_for(boost::chrono::milliseconds(200));
}
}

template <typename T> void storeResultIn(T& a) {
std::fill(begin(a), end(a), '4');
}

int main()
{
asio::io_service iosvc;
tcp::socket s(iosvc);
tcp::resolver r(iosvc);

tcp::acceptor a(iosvc, tcp::endpoint(tcp::v4(), 6767));

a.accept(s);
{
asio::spawn(iosvc, [&iosvc,&s](asio::yield_context yield)
{
char data[256];
while (s.is_open())
{
size_t n = s.async_read_some(boost::asio::buffer(data), yield);

if (boost::algorithm::starts_with(data, "computePi"))
{
iosvc.post([]{std::cout << "I can still breath\n";}); // some demo work
iosvc.post([]{std::cout << "And be responsive\n";});

while (!computationFinished)
{
computeSomeMore();
iosvc.poll_one(); // this enables the demo work to be run
}

storeResultIn(data);
boost::asio::async_write(s, boost::asio::buffer(data, n), yield);
} else
{
std::cout << "Received unknown command '" << std::string(data, data+n) << "'\n";
}
}
});
}

iosvc.run();
std::cout << "Bye bye\n";
}

Когда отправляется «computePi», сервер печатает:

Calculating...
I can still breath
Calculating...
And be responsive
Calculating...
Calculating...
Calculating...
Calculating...
Calculating...
Calculating...
Calculating...
Calculating...
Calculating...
Calculation finished
4