Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Boost Asio, Multiple threads and multiple io_service

I want to develop a server use multiple threads and multiple io_service instance(each thread use an io_service instance) to listen at a port. For each io_service instance I create a corresponding boost::asio::ip::tcp::acceptor object. I try this code:

 using namespace boost::asio;
    ...
    io_service io_service_;
    io_service io_service_1;

    ip::tcp::acceptor* acceptor_;
    acceptor_ = new ip::tcp::acceptor(io_service_);
    ip::tcp::endpoint ep( ip::tcp::v4(), LISTEN_PORT);
    acceptor_->open(ep.protocol());
    acceptor_->bind(ep);
    acceptor_->listen();

    ip::tcp::acceptor* acceptor_1;
    acceptor_1 = new ip::tcp::acceptor(io_service_1);
    acceptor_1->open(ep.protocol());
    acceptor_1->bind(ep);
    acceptor_1->listen();
    ...

    boost::thread th( boost::bind(&io_service::run, &io_service_));
    boost::thread th( boost::bind(&io_service::run, &io_service_1));
    ...

when running will display error dialog:

boost::exception_detail::clone_impl< boost::exception_detail::error_info_injector > at memory location 0x001FF704.

can you help me how to make a server with Multiple threads, each thread use an io_service instance?

Update: as I read in Boost.Asio C++ Network Programming, have 3 way to use io_service with thread:

  1. Single-thread with one io_service and one handler thread(thread running io_service::run())
  2. Multi-threaded with a single io_service instance and several handler threads
  3. Multi-threaded with several io_service instances and several threads

I can implement case 1 and 2. But with case 3, I don't know how to implement it to handle many concurrent connections, should I use 1 thread to handle 1 io_service(as above)? Is case 3 has better performance(can handle more concurrent connections) than case 2?

like image 484
Ikarus Avatar asked Nov 04 '15 18:11

Ikarus


People also ask

Is boost asio multithreaded?

Multithreading, synchronizing, and handler - 2020. The boost. asio starts asynchronous operations rather than calling blocking functions in a sequential manner.

Is boost :: asio :: Io_service thread safe?

It is safe to post handlers from within a handler for a single instance of an io_service according to the documentation.

Is asio multithreaded?

Asio multithreaded environment. The only thing you need to get your completion handlers synchronized properly is io_context::strand class instance. It works pretty simple: completion handlers attached to the same io_context::strand will be invoked serially.

Is boost asio thread safe?

Thread Safety Like a regular Boost. Asio socket, a stream is not thread safe. Callers are responsible for synchronizing operations on the socket using an implicit or explicit strand, as per the Asio documentation.

Can I create multiple I/O service objects in boost ASIO?

Calling run () repeatedly on a single I/O service object is the recommended method to make a program based on Boost.Asio more scalable. However, instead of providing several threads to one I/O service object, you could also create multiple I/O service objects.

How do multiple threads work with I/O services?

If the member function run () is called on an object of type boost::asio::io_service, the associated handlers are invoked within the same thread. By using multiple threads, a program can call run () multiple times. Once an asynchronous operation is complete, the I/O service object will execute the handler in one of these threads.

What is asynchronous data processing in boost ASIO?

Programs that use Boost.Asio for asynchronous data processing are based on I/O services and I/O objects. I/O services abstract the operating system interfaces that process data asynchronously. I/O objects initiate asynchronous operations.

What are the advantages of using threads in boost ASIO?

If threads are used, several functions can be executed concurrently on available CPU cores. Boost.Asio with threads improves the scalability because your program can take advantage of internal and external devices that can execute operations independently or in cooperation with each other.


2 Answers

You can use multiple threads, but you need to use 1 acceptor for a port.

IO services are thread-safe, so you can use one service on many threads.

You can even have multiple io services, no problem. You can't bind multiple acceptors to the same port though (unless you bind to different logical network interfaces, perhaps, but that's not really "the same port" then).

#include <boost/asio.hpp>
#include <boost/thread.hpp>

using namespace boost::asio;
using namespace boost;

int main() {
    io_service io_service_;

    ip::tcp::acceptor acceptor_(io_service_, { {}, 6767 });
    acceptor_.bind({ ip::tcp::v4(), 6767 });

    boost::thread_group tg;
    for (unsigned i = 0; i < thread::hardware_concurrency(); ++i)
        tg.create_thread(boost::bind(&io_service::run, &io_service_));

    // ...
    //
    tg.join_all();
}
like image 179
sehe Avatar answered Oct 23 '22 00:10

sehe


You can only have one acceptor listening on a given port. If you want to handle multiple clients with one port, you'll need to set the option reuse_address on your acceptor. That way the socket you pass to async_accept() will use a different port, leaving your listen port free to accept a connection from another client.

boost::asio::io_service ios_;
boost::asio::ip::tcp::acceptor acceptor_(ios_);

void handle_client(boost::shared_pointer<boost::asio::ip::tcp::socket> sock);
void start_accept();

int main() {
    boost::asio::ip::tcp::endpoint ep(ip::tcp::v4(), LISTEN_PORT);
    acceptor_.open(ep.protocol());
    acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true));
    acceptor_.bind(ep);
    acceptor_.listen();
    boost::thread_group threads;
    for (int i = 0; i < NUM_WORKER_THREADS; ++i) {
        threads.create_thread(boost::bind(&io_service::run, &ios_));
    }
    start_accept();
    threads.join_all();
}

void start_accept() {
    boost::shared_pointer<boost::asio::ip::tcp::socket> sock(ios_);
    acceptor_.async_accept(*sock, boost::bind(handle_client, sock));
}

void handle_client(boost::shared_pointer<boost::asio::ip::tcp::socket> sock) {
    start_accept();
    // talk to the client
}

See Boost's HTTP server example for a more complete example.

like image 5
Miles Budnek Avatar answered Oct 22 '22 22:10

Miles Budnek