-
Notifications
You must be signed in to change notification settings - Fork 14
Open
Description
I think it's a good idea to have two io_context.
One for accepting new connections (maybe also signal handler),
and one for sessions.
Currently I am using something like this:
int main(int argc, char *argv[]) {
namespace ba = boost::asio;
using tcp = ba::ip::tcp;
// Only for acceptor (maybe also signal handler)
ba::io_context ctx_accpetor{1};
tcp::acceptor acceptor(ctx_accpetor);
std::const_view address{"::"};
constexpr uint16_t port{8081};
// Start listen before allocate any resources
// If we can't bind exit/throw
tcp::endpoint ep;
try {
ep = {ba::ip::make_address(address), port};
acceptor.open(ep.protocol());
acceptor.set_option(ba::socket_base::reuse_address{true});
acceptor.bind(ep);
acceptor.listen();
} catch (const std::exception &e) {
std::cerr << "[" << address <<"]:" << port <<" " << e.what() << '\n';
return 1;
}
auto app = expresscpp::ExpressCpp();
app.Use([](const auto & /*req*/, const auto &res, const Next & /*next*/) {
res->Json("{}");
});
auto thn = std::thread::hardware_concurrency;
// Only for sessions
ba::io_context ctx_sessions{htn};
// Keep ctx_sessions running (wait for new sessions to spawn)
auto work_guard = boost::asio::make_work_guard(ctx_sessions);
// Start all workers
std::vector<std::thread> workers;
workers.reserve(thn);
for (uint32_t i = 0; i < htn; ++i) {
workers.emplace_back(std::thread([&ctx_sessions] { ctx_sessions.run(); }));
}
// Accpet only on one thread (no need for strand, std::mutex)
using AcceptHandler = std::function<void(const boost::system::error_code &, ba::ip::tcp::socket)>;
AcceptHandler handler = [&](const auto &ec, auto peer) {
if (!ec) {
std::make_shared<expresscpp::Session>(std::move(peer), &app)->run();
acceptor.async_accept(ctx_sessions, handler);
}
};
acceptor.async_accept(ctx_sessions, handler);
// attach signals to ctx_accpetor and thread
ba::signal_set signal_set(ctx_accpetor, SIGINT, SIGTERM, SIGQUIT);
signal_set.async_wait([&acceptor](boost::system::error_code const &, int /*sig*/) {
boost::system::error_code ec;
acceptor.cancel(ec);
acceptor.close(ec);
});
// Start Accept
ctx_accpetor.run();
// Acceptor is cancelled
// Retire guard
work_guard.reset();
// Wait for all sessions to finish gracefully
for (auto i = workers.size(); i--;) {
workers.at(i).join();
}
return 0;
}Metadata
Metadata
Assignees
Labels
No labels