c++ - how to do boost::asio::spawn with io_service-per-CPU? -
my server based on boost spawn echo server.
the server runs fine on single-core machine, not 1 crash several months. when takes 100% cpu still works fine.
but need handle more client requests, use multi-core machine. use cpus run io_service
on several thread, this:
#include <boost/asio/io_service.hpp> #include <boost/asio/ip/tcp.hpp> #include <boost/asio/spawn.hpp> #include <boost/asio/steady_timer.hpp> #include <boost/asio/write.hpp> #include <boost/thread/thread.hpp> #include <iostream> #include <memory> #include <thread> using namespace std; using boost::asio::ip::tcp; class session : public std::enable_shared_from_this<session>{ public: explicit session(tcp::socket socket) : socket_(std::move(socket)), timer_(socket_.get_io_service()), strand_(socket_.get_io_service()) {} void go() { auto self(shared_from_this()); boost::asio::spawn(strand_, [this, self](boost::asio::yield_context yield) { try { char data[1024] = {'3'}; for( ; ;) { timer_.expires_from_now(std::chrono::seconds(10)); std::size_t n = socket_.async_read_some(boost::asio::buffer(data, sizeof(data)), yield); // data // write boost::asio::async_write(socket_, boost::asio::buffer(data, sizeof(data)), yield); } } catch(...) { socket_.close(); timer_.cancel(); } }); boost::asio::spawn(strand_, [this, self](boost::asio::yield_context yield) { while(socket_.is_open()) { boost::system::error_code ignored_ec; timer_.async_wait(yield[ignored_ec]); if(timer_.expires_from_now() <= std::chrono::seconds(0)) socket_.close(); } }); } private: tcp::socket socket_; boost::asio::steady_timer timer_; boost::asio::io_service::strand strand_; }; int main(int argc, char* argv[]) { try { boost::asio::io_service io_service; boost::asio::spawn(io_service, [&](boost::asio::yield_context yield) { tcp::acceptor acceptor(io_service, #define port "7788" tcp::endpoint(tcp::v4(), std::atoi(port))); for( ; ;) { boost::system::error_code ec; tcp::socket socket(io_service); acceptor.async_accept(socket, yield[ec]); if(!ec) // std::make_shared<session>(std::move(socket))->go(); io_service.post(boost::bind(&session::go, std::make_shared<session>(std::move(socket)))); } }); // ----------- works fine on single-core machine ------------ { // io_service.run(); } // ----------- crashes (with multi core) ---------- { auto thread_count = std::thread::hardware_concurrency(); // multi core boost::thread_group threads; for(auto = 0; < thread_count; ++i) threads.create_thread(boost::bind(&boost::asio::io_service::run, &io_service)); threads.join_all(); } } catch(std::exception& e) { std::cerr << "exception: " << e.what() << "\n"; } return 0; }
the code works fine on single-core maching, crashes time on 2-core/4-core/8-core machine. crash dump don't see related code, boost::spawn , randomly named lambda.
so want try this: run io_service
per cpu.
i found demo, uses async function:
void server::start_accept() { new_connection_.reset(new connection( io_service_pool_.get_io_service(), request_handler_)); acceptor_.async_accept(new_connection_->socket(), boost::bind(&server::handle_accept, this, boost::asio::placeholders::error)); } void server::handle_accept(const boost::system::error_code& e) { if (!e) { new_connection_->start(); } start_accept(); }
the io_service_pool_.get_io_service()
randomly pickup io_service
, code uses spawn
boost::asio::spawn(io_service, ...
how spawn
random io_service
?
seems asking wrong question, spawn
cannot work multiple io_service
, socket
can. modified code this:
int main(int argc, char* argv[]) { try { boost::asio::io_service io_service; boost::asio::io_service::work work(io_service); auto core_count = std::thread::hardware_concurrency(); // io_service_pool.hpp , io_service_pool.cpp boost's example io_service_pool pool(core_count); boost::asio::spawn(io_service, [&](boost::asio::yield_context yield) { #define port "7788" tcp::acceptor acceptor(io_service, tcp::endpoint(tcp::v4(), std::atoi(port))); for( ; ;) { boost::system::error_code ec; boost::asio::io_service& ios = pool.get_io_service(); tcp::socket socket(ios); acceptor.async_accept(socket, yield[ec]); if(!ec) ios.post(boost::bind(&session::go, std::make_shared<session>(std::move(socket)))); } }); { // run io_service thread t([&] { pool.run(); }); t.detach(); io_service.run(); } } catch(std::exception& e) { std::cerr << "exception: " << e.what() << "\n"; } return 0; }
now server doesn't crash anymore. still have no idea cause crash if use single io_service
threads.
Comments
Post a Comment