Asio multithreaded server: problem persists, sample program

I made the test with the CVS version of boost and I still fall in the problem that I have reported some days ago :( Btw I think that a bug in the Windows API GetQueuedCompletionStatus sounds very strange to me because I think that implementations like this one are very common or I'm wrong? ////////////////////////////////////////////////////////////////////////////////////////////////////////// #include "boost/asio.hpp" #include "boost/thread.hpp" #include "boost/bind.hpp" ////////////////////////////////////////////////////////////////////////////////////////////////////////// class Session { public: Session(boost::asio::io_service &service) : m_socket(service) { } ~Session() { m_socket.close(); } boost::asio::ip::tcp::socket & socket() { return m_socket; } void run() { m_socket.async_read_some(boost::asio::buffer(m_buffer), boost::bind(&Session::read_handler, this, _1, _2)); } std::string generate_response() { Sleep(10000); // It takes a lot of time to say Hello :) static int counter = 0; counter++; std::stringstream stream; stream << "<html><body><h2>Hello " << counter << "</h2></body></html>"; return stream.str(); } void read_handler(const boost::system::error_code &e, size_t bytes_transferred) { if(!e) { boost::asio::async_write(m_socket, boost::asio::buffer(generate_response()), boost::bind(&Session::write_handler, this, _1, _2)); } } void write_handler(const boost::system::error_code &e, size_t bytes_transferred) { delete this; } private: boost::asio::ip::tcp::socket m_socket; boost::array<char, 8192> m_buffer; }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// class Server { public: Server(int port) : m_service(), m_acceptor(m_service) { boost::asio::ip::tcp::endpoint endpoint(boost::asio::ip::tcp::v4(), port); m_acceptor.open(endpoint.protocol()); m_acceptor.bind(endpoint); m_acceptor.listen(); accept(); } void accept() { Session *connection = new Session(m_service); m_acceptor.async_accept(connection->socket(), boost::bind(&Server::accept_handler, this, _1, connection)); } void run(int threads = 10) { boost::thread_group threads_pool; while(threads-- > 0) threads_pool.create_thread(boost::bind(&boost::asio::io_service::run, &m_service)); m_service.run(); } void accept_handler(const boost::system::error_code &e, Session *connection) { if(!e) { connection->run(); accept(); } } protected: boost::asio::io_service m_service; boost::asio::ip::tcp::acceptor m_acceptor; }; ////////////////////////////////////////////////////////////////////////////////////////////////////////// int main(int argc, char *argv) { Server server(7070); server.run(); return 0; } ////////////////////////////////////////////////////////////////////////////////////////////////////////// As reported in my previous message all handlers are invoked with the params _1/_2 due to a multiple definition link error. Bye

berserker_r wrote:
I made the test with the CVS version of boost and I still fall in the problem that I have reported some days ago :( Btw I think that a bug in the Windows API GetQueuedCompletionStatus sounds very strange to me because I think that implementations like this one are very common or I'm wrong?
Well in your case the long running operation isn't CPU bound since it calls Sleep(). That's why I asked about it early on in this discussion, because the only way I could reproduce the behaviour was to make it CPU bound (e.g. an infinite loop "while (true) ;"). Anyway, you have a bug in your program which is probably not related to your problem:
std::string generate_response() { Sleep(10000); // It takes a lot of time to say Hello :) static int counter = 0; counter++; std::stringstream stream; stream << "<html><body><h2>Hello " << counter << "</h2></body></html>"; return stream.str(); }
void read_handler(const boost::system::error_code &e, size_t bytes_transferred) { if(!e) { boost::asio::async_write(m_socket, boost::asio::buffer(generate_response()), boost::bind(&Session::write_handler, this, _1, _2)); } }
The string returned by generate_response() goes out of scope before the asynchronous operation completes. The simplest way to fix it would be to add a std::string data member to the Session class and change read_handler to look like this: void read_handler(const asio::error_code &e, size_t bytes_transferred) { if(!e) { m_message = generate_response(); boost::asio::async_write(m_socket, asio::buffer(m_message), boost::bind(&Session::write_handler, this, _1, _2)); } } I fixed this in my copy before trying it, and I am unable to reproduce the problem you described before. The subsequent accept operation works just fine. Can you please send step-by-step instructions for how you reproduce it with this program and exactly what behaviour you see, thanks. Cheers, Chris

Christopher Kohlhoff wrote:
Well in your case the long running operation isn't CPU bound since it calls Sleep(). That's why I asked about it early on in this discussion, because the only way I could reproduce the behaviour was to make it CPU bound (e.g. an infinite loop "while (true) ;").
What's the "implementation" difference from sleeping a long time and an infinite loop? The sleep call could be replaced by a lock on a mutex that takes a lot of time to acquire the access, does that make difference? I always need to be free to accept new connections... Thanks again for your response, I'll try some more tests soon ;)
participants (2)
-
berserker_r
-
Christopher Kohlhoff