urb
urb

Reputation: 964

Run threads with boost and asio

Introduction

I'm trying create a thread to receive data from socket.

Code

void ClientTcp::read_handler(tcp::socket s){
    for(;;){
        char buffer[max_buffr];
        boost::system::error_code error;
        size_t length = s.read_some(boost::asio::buffer(buffer), error);
        if (error == boost::asio::error::eof)
            break; // Connection closed cleanly by peer.
        else if (error)
            throw boost::system::system_error(error); // Some other error.
        buffer[length] = '\0';
        std::cout << "-> " << buffer << std::endl;
    }
}

void ClientTcp::run(){
    tcp::socket s(io_service_);
    tcp::resolver resolver(io_service_);
    boost::asio::connect(s, resolver.resolve({ip_, port_}));

    boost::thread read_th(read_handler, std::move(s));
    std::string message;
    for(;;){
        std::cin >> message;
        boost::asio::write(s, boost::asio::buffer(message, message.size()));
    }
    read_th.join();
}

Problem

This line boost::thread read_th(read_handler, std::move(s)); has a bug that i can't understand.

Error no matching function for call to boost::thread::thread(<unresolved overloaded function type, std::remove_reference<boost::asio::basic_stream_socket<boost::asio::ip::tcp>&>::type)

Main Question How I launch a thread from class method ?

Upvotes: 2

Views: 720

Answers (2)

Igor R.
Igor R.

Reputation: 15075

It seems that boost::thread constructor is unable to perform "perfect forwarding" of its arguments (and you can't use bind for the reason described in the comments to @sehe answer).

However, being a part of C++11, std::thread does forward the arguments correctly, so the following compiles:

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

using namespace boost::asio;

void read_handler(ip::tcp::socket && s)
{
} 

int main()
{
    io_service io;
    ip::tcp::socket s(io);
    std::thread read_th(read_handler, std::move(s));
}

Note that if read_handler is a non-static member function (like in your question), you should bind it with the object instance: std::thread(&ClientTcp::read_handler, this, std::move(s));

(Of course, the object lifespan should be taken into account, as well as the design considerations raised by @sehe.)

Upvotes: 0

sehe
sehe

Reputation: 392999

To answer the wrong question: You'd use boost::bind

boost::thread read_th(boost::bind(&ClientTcp::read_handler, this, std::move(s)));

But you certainly do not want to do that. Use a thread per asynchronous operation doesn't work at all.

Boost let's you achieve asynchrony without the need for additional threads. Just use the async_* functions instead of the functions you re using:

  • async_read_some
  • async_write.

Don't forget to run io_service::run().

Upvotes: 2

Related Questions