Это не будет делать то, что вы ожидаете.
Например, с одним циклом async_accept
вы бы никогда не достигли точки "никакой другой работы дляdo ".
Аналогично, если только одна сторона владеет выдающимися work<>
( документами и почему ), ситуация никогда не возникнетгде «нет никакой другой работы».
По сути, вы действительно хотите связать опрос:
template <typename Condition, typename Handler, typename Executor>
void run_when(Executor& ex, Condition c, Handler h) {
struct Op {
Executor& _executor;
Condition _cond;
Handler _handler;
Op(Executor& ex, Condition c, Handler h)
: _executor(ex), _cond(std::move(c)), _handler(std::move(h))
{ }
void operator()() const {
if (_cond())
_handler(error_code{});
else
ba::post(_executor, std::move(*this));
}
};
ba::post(ex, Op{ex, std::move(c), std::move(h)});
}
Это можно использовать как:
run_when(io,
[&] { return bool(triggered); },
[](error_code ec) { std::clog << "triggered: " << ec.message() << "\n"; });
Демо
Live On Coliru
#include <boost/asio.hpp>
namespace ba = boost::asio;
using boost::system::error_code;
using namespace std::chrono_literals;
template <typename Condition, typename Handler, typename Executor>
void run_when(Executor& ex, Condition c, Handler h) {
struct RunWhen {
Executor& _executor;
Condition _cond;
Handler _handler;
RunWhen(Executor& ex, Condition c, Handler h)
: _executor(ex), _cond(std::move(c)), _handler(std::move(h))
{ }
void operator()() const {
if (_cond())
_handler(error_code{});
else
ba::post(_executor, std::move(*this));
}
};
ba::post(ex, RunWhen{ex, std::move(c), std::move(h)});
}
#include <iostream>
int main() {
// some state that gets changed in the background
std::atomic_bool triggered { false };
std::thread([&] {
std::this_thread::sleep_for(1.5s);
triggered = true;
}).detach();
ba::io_context io;
// just some background polling that shall not block other work
run_when(io, [&] { return bool(triggered); }, [](error_code ec) { std::clog << "triggered: " << ec.message() << "\n"; });
io.run_for(3s);
}
Печать (через ~ 1,5 с):
triggered: Success
БОНУС
Почему наш обработчик принимает код ошибки?Ну, в соответствии с другими операциями Asio, вы можете отменить их.Либо вы берете на себя ответственность за продление срока действия экземпляра run_when<>(...)::Op
, что усложняет жизнь.Или вы можете сделать так, чтобы вызываемый Condition
мог вернуть код, указывающий, было ли выполнено условие или было отменено ожидание¹:
Live On Coliru
#include <boost/asio.hpp>
namespace ba = boost::asio;
using boost::system::error_code;
using boost::system::system_error;
using ba::error::operation_aborted;
using namespace std::chrono_literals;
template <typename Condition, typename Handler, typename Executor>
void run_when(Executor& ex, Condition c, Handler h) {
struct Op {
Executor& _executor;
Condition _cond;
Handler _handler;
Op(Executor& ex, Condition c, Handler h)
: _executor(ex), _cond(std::move(c)), _handler(std::move(h))
{ }
void operator()() const {
try {
if (_cond())
_handler(error_code{});
else
ba::post(_executor, std::move(*this));
} catch(system_error const& se) {
_handler(se.code());
}
}
};
ba::post(ex, Op{ex, std::move(c), std::move(h)});
}
#include <random>
auto random_delay() {
static std::mt19937 engine(std::random_device{}());
return (std::uniform_int_distribution<>(1,2)(engine)) * 1s;
}
#include <iostream>
int main() {
// some state that gets changed in the background
std::atomic_bool triggered { false }, canceled { false };
std::thread([&] { std::this_thread::sleep_for(1.5s); triggered = true; }).detach();
// add a randomized cancellation
{
auto cancel_time = random_delay();
std::clog << "hammer time: " << (cancel_time/1.0s) << "s\n";
std::thread([&] { std::this_thread::sleep_for(cancel_time); canceled = true; }).detach();
}
ba::io_context io;
// just some background polling that shall not block other work
auto condition = [&] { return canceled? throw system_error(operation_aborted) : bool(triggered); };
run_when(io, condition, [](error_code ec) { std::clog << "handler: " << ec.message() << "\n"; });
io.run_for(3s);
}
Который печатает
hammer time: 1s
handler: Success
или
hammer time: 2s
handler: Success
в зависимости от значения random_delay()
.
¹ (или что дочь мэра развелась, потому что код ошибки довольно универсален)