Crash : terminate called after throwing an instance of 'std::system_error' what(): Resource deadlock avoided

10,127

@sehe .. can you run the code and let me know how to overcome the crash that I mentioned ? – Nishant Sharma

Actually, no I won't. The problem has already been analyzed: you can't join the current thread (it would deadlock).

But I can do something better:

Grabbing my crystal ball, I can guess you got this example from a particular book, named Boost.Asio C++ Network Programming Cookbook¹, around page 139.

I recognized it after a while when I added up all the code smells (delete this and m_stop.load() tipped me over the edge).

The good news is, I reviewed that code before:

ASIO example code closing socket before it should

You can probably profit from the particular comments I made there.

¹ from packtpub: https://www.packtpub.com/application-development/boostasio-c-network-programming-cookbook

Share:
10,127
Nishant Sharma
Author by

Nishant Sharma

Updated on June 05, 2022

Comments

  • Nishant Sharma
    Nishant Sharma almost 2 years

    I have a simple client /server application the code of which is mentioned below. Please run the server in one shell and the client in another shell in linux. First start the server and then the client. When the server is done with it's work, it crashes with following exception:

    terminate called after throwing an instance of 'std::system_error' what(): Resource deadlock avoided

    This happens from the line m_thread->join() from inside the function Service::HandleClient I have no clue on what's going on.. Can someone please check the code.. I just want that the server application should also get closed correctly the way the client application got closed.

    **Server Code : **

    #include <boost/asio.hpp>
    
    #include <thread>
    #include <atomic>
    #include <memory>
    #include <iostream>
    
    using namespace boost;
    
    class Service {
    public:
        Service(){}
    
        void StartHandligClient(
            std::shared_ptr<asio::ip::tcp::socket> sock) {
    
            m_thread.reset(new std::thread (([this, sock]() {
                HandleClient(sock);
            })) );
    
        }
    
    private:
        void HandleClient(std::shared_ptr<asio::ip::tcp::socket> sock) {
            while(1)
            {
                try {
                    asio::streambuf request;
                    std::cout << "Waiting to read \n";
                    asio::read_until(*sock.get(), request, '\n');
    
                    std::string s( (std::istreambuf_iterator<char>(&request)), std::istreambuf_iterator<char>() );
                    std::cout << "Server got : " << s << "\n";
    
                    // Emulate request processing.
                    int i = 0;
                    while (i != 1000000)
                        i++;
    
                    std::this_thread::sleep_for(
                            std::chrono::milliseconds(500));
    
                    // Sending response.
                    std::string response = "Response\n";
                    asio::write(*sock.get(), asio::buffer(response));
                }
                catch (system::system_error &e) {
                    boost::system::error_code ec = e.code();
                    if(ec == asio::error::eof)
                    {
                        std::cout << "Breaking loop \n";
                        break;
                    }
                    std::cout << "Error occured! Error code = "
                        << e.code() << ". Message: "
                        << e.what();
                }
            }
    
            m_thread->join();
    
            // Clean-up.
            delete this;
        }
        std::unique_ptr<std::thread> m_thread;
    };
    
    class Acceptor {
    public:
        Acceptor(asio::io_service& ios, unsigned short port_num) :
            m_ios(ios),
            m_acceptor(m_ios,
            asio::ip::tcp::endpoint(
            asio::ip::address_v4::any(),
            port_num))
        {
            m_acceptor.listen();
        }
    
        void Accept() {
            std::cout << "Server Accept() \n" << std::flush;
            std::shared_ptr<asio::ip::tcp::socket>
                sock(new asio::ip::tcp::socket(m_ios));
    
            std::cout << "BEFORE calling acceptor's accept function \n" << std::flush;
            m_acceptor.accept(*sock.get());
            std::cout << "AFTER calling acceptor's accept function \n" << std::flush;
    
    
            (new Service)->StartHandligClient(sock);
        }
    
        void close()
        {
            std::cout << "Inside Acceptor.close() \n" << std::flush;
            m_acceptor.close();
        }
    
    private:
        asio::io_service& m_ios;
        asio::ip::tcp::acceptor m_acceptor;
    };
    
    class Server {
    public:
        Server() : m_stop(false) {}
    
        void Start(unsigned short port_num) {
            m_thread.reset(new std::thread([this, port_num]() {
                Run(port_num);
            }));
        }
    
        void Stop() {
            m_stop.store(true);
            m_thread->join();
        }
    
    private:
        void Run(unsigned short port_num) {
            Acceptor acc(m_ios, port_num);
    
            while (!m_stop.load()) {
                std::cout << "Server accept\n" << std::flush;
                acc.Accept();
            }
            acc.close();
        }
    
        std::unique_ptr<std::thread> m_thread;
        std::atomic<bool> m_stop;
        asio::io_service m_ios;
    };
    
    int main()
    {
        unsigned short port_num = 3333;
    
        try {
            Server srv;
            srv.Start(port_num);
    
            std::this_thread::sleep_for(std::chrono::seconds(4));
    
            srv.Stop();
        }
        catch (system::system_error &e) {
            std::cout << "Error occured! Error code = "
                << e.code() << ". Message: "
                << e.what();
        }
    
        return 0;
    }
    

    **Client Code : **

    #include <boost/asio.hpp>
    #include <iostream>
    
    using namespace boost;
    
    class SyncTCPClient {
    public:
        SyncTCPClient(const std::string& raw_ip_address,
            unsigned short port_num) :
            m_ep(asio::ip::address::from_string(raw_ip_address),
            port_num),
            m_sock(m_ios) {
    
            m_sock.open(m_ep.protocol());
        }
    
        void connect() {
            m_sock.connect(m_ep);
        }
    
        void close() {
            m_sock.shutdown(
                boost::asio::ip::tcp::socket::shutdown_both);
            m_sock.close();
        }
    
        std::string emulateLongComputationOp(
            unsigned int duration_sec) {
    
            std::string request = "EMULATE_LONG_COMP_OP "
                + std::to_string(duration_sec)
                + "\n";
    
            sendRequest(request);
            return receiveResponse();
        };
    
    private:
        void sendRequest(const std::string& request)
        {
            std::cout << "Inside sendRequest : " << request << "\n";
            asio::write(m_sock, asio::buffer(request));
        }
    
        std::string receiveResponse() {
            asio::streambuf buf;
            asio::read_until(m_sock, buf, '\n');
    
            std::istream input(&buf);
    
            std::string response;
            std::getline(input, response);
    
            return response;
        }
    
    private:
        asio::io_service m_ios;
    
        asio::ip::tcp::endpoint m_ep;
        asio::ip::tcp::socket m_sock;
    };
    
    int main()
    {
        const std::string raw_ip_address = "127.0.0.1";
        const unsigned short port_num = 3333;
    
        try {
            SyncTCPClient client(raw_ip_address, port_num);
    
            // Sync connect.
            client.connect();
    
            std::cout << "Sending request to the server... " << std::endl;
            std::string response = client.emulateLongComputationOp(10);
    
            std::cout << "Response received: " << response << std::endl;
            sleep(2);
    
            // Close the connection and free resources.
            client.close();
        }
        catch (system::system_error &e) {
            std::cout << "Error occured! Error code = " << e.code()
                << ". Message: " << e.what();
    
            return e.code().value();
        }
    
        return 0;
    }